diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index c618f202f9..9f2005f40f 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,12 @@ +2010-11-23: Version 2.5.8 + + Removed dependency on Gay's dtoa. + + Improved heap profiler precision and speed. + + Reduced overhead of callback invocations on ARM. + + 2010-11-18: Version 2.5.7 Fixed obscure evaluation order bug (issue 931). diff --git a/deps/v8/LICENSE b/deps/v8/LICENSE index e3ed242d42..c1fcb1a146 100644 --- a/deps/v8/LICENSE +++ b/deps/v8/LICENSE @@ -12,9 +12,6 @@ are: based on layout tests from webkit.org which are copyrighted by Apple Computer, Inc. and released under a 3-clause BSD license. - - Dtoa, located under third_party/dtoa. This code is copyrighted by - David M. Gay and released under an MIT license. - - Strongtalk assembler, the basis of the files assembler-arm-inl.h, assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h, assembler-ia32.cc, assembler-ia32.h, assembler.cc and assembler.h. diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h index fb492d955c..72195c44f2 100644 --- a/deps/v8/include/v8-profiler.h +++ b/deps/v8/include/v8-profiler.h @@ -197,8 +197,13 @@ class V8EXPORT HeapGraphEdge { kContextVariable = 0, // A variable from a function context. kElement = 1, // An element of an array. kProperty = 2, // A named object property. - kInternal = 3 // A link that can't be accessed from JS, - // thus, its name isn't a real property name. + kInternal = 3, // A link that can't be accessed from JS, + // thus, its name isn't a real property name + // (e.g. parts of a ConsString). + kHidden = 4, // A link that is needed for proper sizes + // calculation, but may be hidden from user. + kShortcut = 5 // A link that must not be followed during + // sizes calculation. }; /** Returns edge type (see HeapGraphEdge::Type). */ @@ -240,7 +245,8 @@ class V8EXPORT HeapGraphPath { class V8EXPORT HeapGraphNode { public: enum Type { - kInternal = 0, // Internal node, a virtual one, for housekeeping. + kInternal = 0, // For compatibility, will be removed. + kHidden = 0, // Hidden node, may be filtered when shown to user. kArray = 1, // An array of elements. kString = 2, // A string. kObject = 3, // A JS object (except for arrays and strings). @@ -276,16 +282,19 @@ class V8EXPORT HeapGraphNode { /** Returns node's own size, in bytes. */ int GetSelfSize() const; - /** Returns node's network (self + reachable nodes) size, in bytes. */ - int GetReachableSize() const; - /** * Returns node's retained size, in bytes. That is, self + sizes of * the objects that are reachable only from this object. In other * words, the size of memory that will be reclaimed having this node * collected. + * + * Exact retained size calculation has O(N) (number of nodes) + * computational complexity, while approximate has O(1). It is + * assumed that initially heap profiling tools provide approximate + * sizes for all nodes, and then exact sizes are calculated for the + * most 'interesting' nodes. */ - int GetRetainedSize() const; + int GetRetainedSize(bool exact) const; /** Returns child nodes count of the node. */ int GetChildrenCount() const; @@ -304,6 +313,12 @@ class V8EXPORT HeapGraphNode { /** Returns a retaining path by index. */ const HeapGraphPath* GetRetainingPath(int index) const; + + /** + * Returns a dominator node. This is the node that participates in every + * path from the snapshot root to the current node. + */ + const HeapGraphNode* GetDominatorNode() const; }; diff --git a/deps/v8/samples/shell.cc b/deps/v8/samples/shell.cc index 1a13f5f80b..2bdc5a19da 100644 --- a/deps/v8/samples/shell.cc +++ b/deps/v8/samples/shell.cc @@ -37,6 +37,7 @@ bool ExecuteString(v8::Handle source, v8::Handle name, bool print_result, bool report_exceptions); +v8::Handle PrintToInteger(const v8::Arguments& args); v8::Handle Print(const v8::Arguments& args); v8::Handle Read(const v8::Arguments& args); v8::Handle Load(const v8::Arguments& args); @@ -53,7 +54,8 @@ int RunMain(int argc, char* argv[]) { v8::Handle global = v8::ObjectTemplate::New(); // Bind the global 'print' function to the C++ Print callback. global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print)); - // Bind the global 'read' function to the C++ Read callback. +global->Set(v8::String::New("print2int"), v8::FunctionTemplate::New(PrintToInteger)); +// Bind the global 'read' function to the C++ Read callback. global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read)); // Bind the global 'load' function to the C++ Load callback. global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load)); @@ -138,6 +140,16 @@ v8::Handle Print(const v8::Arguments& args) { } +v8::Handle PrintToInteger(const v8::Arguments& args) { + v8::HandleScope handle_scope; + v8::String::Utf8Value str(args[0]); + const char* cstr = ToCString(str); + printf("%s -> %d\n", cstr, args[0]->ToInt32()->Value()); + fflush(stdout); + return v8::Undefined(); +} + + // The callback that is invoked by v8 whenever the JavaScript 'read' // function is called. This function loads the content of the file named in // the argument into a JavaScript string. diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index 316387fa23..98e0a0ffa4 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -298,14 +298,8 @@ def ConfigureObjectFiles(): libraries_src, libraries_empty_src = env.JS2C(['libraries.cc', 'libraries-empty.cc'], library_files, TYPE='CORE') libraries_obj = context.ConfigureObject(env, libraries_src, CPPPATH=['.']) - # Build dtoa. - dtoa_env = env.Copy() - dtoa_env.Replace(**context.flags['dtoa']) - dtoa_files = ['dtoa-config.c'] - dtoa_obj = context.ConfigureObject(dtoa_env, dtoa_files) - source_objs = context.ConfigureObject(env, source_files) - non_snapshot_files = [dtoa_obj, source_objs] + non_snapshot_files = [source_objs] # Create snapshot if necessary. For cross compilation you should either # do without snapshots and take the performance hit or you should build a diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 5912449169..b46cd02a3a 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -4669,9 +4669,11 @@ Handle HeapGraphEdge::GetName() const { case i::HeapGraphEdge::kContextVariable: case i::HeapGraphEdge::kInternal: case i::HeapGraphEdge::kProperty: + case i::HeapGraphEdge::kShortcut: return Handle(ToApi(i::Factory::LookupAsciiSymbol( edge->name()))); case i::HeapGraphEdge::kElement: + case i::HeapGraphEdge::kHidden: return Handle(ToApi(i::Factory::NewNumberFromInt( edge->index()))); default: UNREACHABLE(); @@ -4761,15 +4763,9 @@ int HeapGraphNode::GetSelfSize() const { } -int HeapGraphNode::GetReachableSize() const { - IsDeadCheck("v8::HeapSnapshot::GetReachableSize"); - return ToInternal(this)->ReachableSize(); -} - - -int HeapGraphNode::GetRetainedSize() const { +int HeapGraphNode::GetRetainedSize(bool exact) const { IsDeadCheck("v8::HeapSnapshot::GetRetainedSize"); - return ToInternal(this)->RetainedSize(); + return ToInternal(this)->RetainedSize(exact); } @@ -4812,6 +4808,12 @@ const HeapGraphPath* HeapGraphNode::GetRetainingPath(int index) const { } +const HeapGraphNode* HeapGraphNode::GetDominatorNode() const { + IsDeadCheck("v8::HeapSnapshot::GetDominatorNode"); + return reinterpret_cast(ToInternal(this)->dominator()); +} + + const HeapGraphNode* HeapSnapshotsDiff::GetAdditionsRoot() const { IsDeadCheck("v8::HeapSnapshotsDiff::GetAdditionsRoot"); i::HeapSnapshotsDiff* diff = diff --git a/deps/v8/src/apiutils.h b/deps/v8/src/apiutils.h index 1313ddaabe..9683aa43bb 100644 --- a/deps/v8/src/apiutils.h +++ b/deps/v8/src/apiutils.h @@ -58,6 +58,9 @@ class ImplementationUtilities { static v8::Arguments NewArguments(internal::Object** implicit_args, internal::Object** argv, int argc, bool is_construct_call) { + ASSERT(implicit_args[v8::Arguments::kCalleeIndex]->IsJSFunction()); + ASSERT(implicit_args[v8::Arguments::kHolderIndex]->IsHeapObject()); + return v8::Arguments(implicit_args, argv, argc, is_construct_call); } diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index b3b0766a8f..76a610b7be 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -100,8 +100,9 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) { // Create a new closure through the slower runtime call. __ bind(&gc); - __ Push(cp, r3); - __ TailCallRuntime(Runtime::kNewClosure, 2, 1); + __ LoadRoot(r4, Heap::kFalseValueRootIndex); + __ Push(cp, r3, r4); + __ TailCallRuntime(Runtime::kNewClosure, 3, 1); } diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index dd0520feed..3e6743afaf 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -3103,10 +3103,13 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { void CodeGenerator::InstantiateFunction( - Handle function_info) { + Handle function_info, + bool pretenure) { // Use the fast case closure allocation code that allocates in new // space for nested functions that don't need literals cloning. - if (scope()->is_function_scope() && function_info->num_literals() == 0) { + if (scope()->is_function_scope() && + function_info->num_literals() == 0 && + !pretenure) { FastNewClosureStub stub; frame_->EmitPush(Operand(function_info)); frame_->SpillAll(); @@ -3116,7 +3119,10 @@ void CodeGenerator::InstantiateFunction( // Create a new closure. frame_->EmitPush(cp); frame_->EmitPush(Operand(function_info)); - frame_->CallRuntime(Runtime::kNewClosure, 2); + frame_->EmitPush(Operand(pretenure + ? Factory::true_value() + : Factory::false_value())); + frame_->CallRuntime(Runtime::kNewClosure, 3); frame_->EmitPush(r0); } } @@ -3136,7 +3142,7 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { ASSERT(frame_->height() == original_height); return; } - InstantiateFunction(function_info); + InstantiateFunction(function_info, node->pretenure()); ASSERT_EQ(original_height + 1, frame_->height()); } @@ -3147,7 +3153,7 @@ void CodeGenerator::VisitSharedFunctionInfoLiteral( int original_height = frame_->height(); #endif Comment cmnt(masm_, "[ SharedFunctionInfoLiteral"); - InstantiateFunction(node->shared_function_info()); + InstantiateFunction(node->shared_function_info(), false); ASSERT_EQ(original_height + 1, frame_->height()); } @@ -5816,6 +5822,15 @@ void CodeGenerator::GenerateGetCachedArrayIndex(ZoneList* args) { } +void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList* args) { + ASSERT(args->length() == 2); + Load(args->at(0)); + Register value = frame_->PopToRegister(); + __ LoadRoot(value, Heap::kUndefinedValueRootIndex); + frame_->EmitPush(value); +} + + void CodeGenerator::VisitCallRuntime(CallRuntime* node) { #ifdef DEBUG int original_height = frame_->height(); diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h index 2e8f46668c..6905d2331e 100644 --- a/deps/v8/src/arm/codegen-arm.h +++ b/deps/v8/src/arm/codegen-arm.h @@ -449,7 +449,8 @@ class CodeGenerator: public AstVisitor { void DeclareGlobals(Handle pairs); // Instantiate the function based on the shared function info. - void InstantiateFunction(Handle function_info); + void InstantiateFunction(Handle function_info, + bool pretenure); // Support for type checks. void GenerateIsSmi(ZoneList* args); @@ -528,6 +529,7 @@ class CodeGenerator: public AstVisitor { void GenerateHasCachedArrayIndex(ZoneList* args); void GenerateGetCachedArrayIndex(ZoneList* args); + void GenerateFastAsciiArrayJoin(ZoneList* args); // Simple condition analysis. enum ConditionAnalysis { diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index c50f84ad5e..f04015bd78 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -860,18 +860,23 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { } -void FullCodeGenerator::EmitNewClosure(Handle info) { +void FullCodeGenerator::EmitNewClosure(Handle info, + bool pretenure) { // Use the fast case closure allocation code that allocates in new // space for nested functions that don't need literals cloning. - if (scope()->is_function_scope() && info->num_literals() == 0) { + if (scope()->is_function_scope() && + info->num_literals() == 0 && + !pretenure) { FastNewClosureStub stub; __ mov(r0, Operand(info)); __ push(r0); __ CallStub(&stub); } else { __ mov(r0, Operand(info)); - __ Push(cp, r0); - __ CallRuntime(Runtime::kNewClosure, 2); + __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex + : Heap::kFalseValueRootIndex); + __ Push(cp, r0, r1); + __ CallRuntime(Runtime::kNewClosure, 3); } context()->Plug(r0); } @@ -2772,6 +2777,13 @@ void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList* args) { } +void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList* args) { + __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); + context()->Plug(r0); + return; +} + + void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { Handle name = expr->name(); if (name->length() > 0 && name->Get(0) == '_') { diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index a0ef80a0fd..f3f7a5d4b3 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -598,8 +598,8 @@ static void GenerateFastApiCall(MacroAssembler* masm, int argc) { // Get the function and setup the context. JSFunction* function = optimization.constant_function(); - __ mov(r7, Operand(Handle(function))); - __ ldr(cp, FieldMemOperand(r7, JSFunction::kContextOffset)); + __ mov(r5, Operand(Handle(function))); + __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset)); // Pass the additional arguments FastHandleApiCall expects. bool info_loaded = false; @@ -607,18 +607,18 @@ static void GenerateFastApiCall(MacroAssembler* masm, if (Heap::InNewSpace(callback)) { info_loaded = true; __ Move(r0, Handle(optimization.api_call_info())); - __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset)); + __ ldr(r7, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset)); } else { - __ Move(r6, Handle(callback)); + __ Move(r7, Handle(callback)); } Object* call_data = optimization.api_call_info()->data(); if (Heap::InNewSpace(call_data)) { if (!info_loaded) { __ Move(r0, Handle(optimization.api_call_info())); } - __ ldr(r5, FieldMemOperand(r0, CallHandlerInfo::kDataOffset)); + __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset)); } else { - __ Move(r5, Handle(call_data)); + __ Move(r6, Handle(call_data)); } __ add(sp, sp, Operand(1 * kPointerSize)); @@ -1082,10 +1082,9 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, // Push the arguments on the JS stack of the caller. __ push(receiver); // Receiver. - __ push(reg); // Holder. - __ mov(ip, Operand(Handle(callback))); // callback data - __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset)); - __ Push(ip, reg, name_reg); + __ mov(scratch3, Operand(Handle(callback))); // callback data + __ ldr(ip, FieldMemOperand(scratch3, AccessorInfo::kDataOffset)); + __ Push(reg, ip, scratch3, name_reg); // Do tail-call to the runtime system. ExternalReference load_callback_property = @@ -1208,15 +1207,15 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, // holder_reg is either receiver or scratch1. if (!receiver.is(holder_reg)) { ASSERT(scratch1.is(holder_reg)); - __ Push(receiver, holder_reg, scratch2); - __ ldr(scratch1, - FieldMemOperand(holder_reg, AccessorInfo::kDataOffset)); - __ Push(scratch1, name_reg); + __ Push(receiver, holder_reg); + __ ldr(scratch3, + FieldMemOperand(scratch2, AccessorInfo::kDataOffset)); + __ Push(scratch3, scratch2, name_reg); } else { __ push(receiver); - __ ldr(scratch1, - FieldMemOperand(holder_reg, AccessorInfo::kDataOffset)); - __ Push(holder_reg, scratch2, scratch1, name_reg); + __ ldr(scratch3, + FieldMemOperand(scratch2, AccessorInfo::kDataOffset)); + __ Push(holder_reg, scratch3, scratch2, name_reg); } ExternalReference ref = @@ -1360,10 +1359,11 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, // ----------- S t a t e ------------- // -- r2 : name // -- lr : return address + // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) + // -- ... + // -- sp[argc * 4] : receiver // ----------------------------------- - // TODO(639): faster implementation. - // If object is not an array, bail out to regular call. if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value(); @@ -1371,20 +1371,133 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, GenerateNameCheck(name, &miss); + Register receiver = r1; + // Get the receiver from the stack const int argc = arguments().immediate(); - __ ldr(r1, MemOperand(sp, argc * kPointerSize)); + __ ldr(receiver, MemOperand(sp, argc * kPointerSize)); // Check that the receiver isn't a smi. - __ tst(r1, Operand(kSmiTagMask)); - __ b(eq, &miss); + __ BranchOnSmi(receiver, &miss); // Check that the maps haven't changed. - CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss); + CheckPrototypes(JSObject::cast(object), receiver, + holder, r3, r0, r4, name, &miss); - __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush), - argc + 1, - 1); + if (argc == 0) { + // Nothing to do, just return the length. + __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); + __ Drop(argc + 1); + __ Ret(); + } else { + Label call_builtin; + + Register elements = r3; + Register end_elements = r5; + + // Get the elements array of the object. + __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); + + // Check that the elements are in fast mode and writable. + __ CheckMap(elements, r0, + Heap::kFixedArrayMapRootIndex, &call_builtin, true); + + if (argc == 1) { // Otherwise fall through to call the builtin. + Label exit, with_write_barrier, attempt_to_grow_elements; + + // Get the array's length into r0 and calculate new length. + __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); + STATIC_ASSERT(kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0); + __ add(r0, r0, Operand(Smi::FromInt(argc))); + + // Get the element's length. + __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset)); + + // Check if we could survive without allocation. + __ cmp(r0, r4); + __ b(gt, &attempt_to_grow_elements); + + // Save new length. + __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); + + // Push the element. + __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize)); + // We may need a register containing the address end_elements below, + // so write back the value in end_elements. + __ add(end_elements, elements, + Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); + const int kEndElementsOffset = + FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize; + __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex)); + + // Check for a smi. + __ BranchOnNotSmi(r4, &with_write_barrier); + __ bind(&exit); + __ Drop(argc + 1); + __ Ret(); + + __ bind(&with_write_barrier); + __ InNewSpace(elements, r4, eq, &exit); + __ RecordWriteHelper(elements, end_elements, r4); + __ Drop(argc + 1); + __ Ret(); + + __ bind(&attempt_to_grow_elements); + // r0: array's length + 1. + // r4: elements' length. + + if (!FLAG_inline_new) { + __ b(&call_builtin); + } + + ExternalReference new_space_allocation_top = + ExternalReference::new_space_allocation_top_address(); + ExternalReference new_space_allocation_limit = + ExternalReference::new_space_allocation_limit_address(); + + const int kAllocationDelta = 4; + // Load top and check if it is the end of elements. + __ add(end_elements, elements, + Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); + __ add(end_elements, end_elements, Operand(kEndElementsOffset)); + __ mov(r7, Operand(new_space_allocation_top)); + __ ldr(r6, MemOperand(r7)); + __ cmp(end_elements, r6); + __ b(ne, &call_builtin); + + __ mov(r9, Operand(new_space_allocation_limit)); + __ ldr(r9, MemOperand(r9)); + __ add(r6, r6, Operand(kAllocationDelta * kPointerSize)); + __ cmp(r6, r9); + __ b(hi, &call_builtin); + + // We fit and could grow elements. + // Update new_space_allocation_top. + __ str(r6, MemOperand(r7)); + // Push the argument. + __ ldr(r6, MemOperand(sp, (argc - 1) * kPointerSize)); + __ str(r6, MemOperand(end_elements)); + // Fill the rest with holes. + __ LoadRoot(r6, Heap::kTheHoleValueRootIndex); + for (int i = 1; i < kAllocationDelta; i++) { + __ str(r6, MemOperand(end_elements, i * kPointerSize)); + } + + // Update elements' and array's sizes. + __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); + __ add(r4, r4, Operand(Smi::FromInt(kAllocationDelta))); + __ str(r4, FieldMemOperand(elements, FixedArray::kLengthOffset)); + + // Elements are in new space, so write barrier is not required. + __ Drop(argc + 1); + __ Ret(); + } + __ bind(&call_builtin); + __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush), + argc + 1, + 1); + } // Handle call cache miss. __ bind(&miss); @@ -1406,28 +1519,68 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, // ----------- S t a t e ------------- // -- r2 : name // -- lr : return address + // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) + // -- ... + // -- sp[argc * 4] : receiver // ----------------------------------- - // TODO(642): faster implementation. - // If object is not an array, bail out to regular call. if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value(); - Label miss; + Label miss, return_undefined, call_builtin; + + Register receiver = r1; + Register elements = r3; GenerateNameCheck(name, &miss); // Get the receiver from the stack const int argc = arguments().immediate(); - __ ldr(r1, MemOperand(sp, argc * kPointerSize)); + __ ldr(receiver, MemOperand(sp, argc * kPointerSize)); // Check that the receiver isn't a smi. - __ tst(r1, Operand(kSmiTagMask)); - __ b(eq, &miss); + __ BranchOnSmi(receiver, &miss); // Check that the maps haven't changed. - CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss); + CheckPrototypes(JSObject::cast(object), + receiver, holder, elements, r4, r0, name, &miss); + + // Get the elements array of the object. + __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); + + // Check that the elements are in fast mode and writable. + __ CheckMap(elements, r0, Heap::kFixedArrayMapRootIndex, &call_builtin, true); + + // Get the array's length into r4 and calculate new length. + __ ldr(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); + __ sub(r4, r4, Operand(Smi::FromInt(1)), SetCC); + __ b(lt, &return_undefined); + + // Get the last element. + __ LoadRoot(r6, Heap::kTheHoleValueRootIndex); + STATIC_ASSERT(kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0); + // We can't address the last element in one operation. Compute the more + // expensive shift first, and use an offset later on. + __ add(elements, elements, Operand(r4, LSL, kPointerSizeLog2 - kSmiTagSize)); + __ ldr(r0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag)); + __ cmp(r0, r6); + __ b(eq, &call_builtin); + + // Set the array's length. + __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); + + // Fill with the hole. + __ str(r6, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag)); + __ Drop(argc + 1); + __ Ret(); + + __ bind(&return_undefined); + __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); + __ Drop(argc + 1); + __ Ret(); + __ bind(&call_builtin); __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop), argc + 1, 1); @@ -2672,7 +2825,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { // -- r1 : receiver // ----------------------------------- Label miss; - __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3); + __ IncrementCounter(&Counters::keyed_load_string_length, 1, r2, r3); // Check the key is the cached one. __ cmp(r0, Operand(Handle(name))); @@ -2680,7 +2833,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { GenerateLoadStringLength(masm(), r1, r2, r3, &miss); __ bind(&miss); - __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3); + __ DecrementCounter(&Counters::keyed_load_string_length, 1, r2, r3); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); @@ -2688,13 +2841,23 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { } -// TODO(1224671): implement the fast case. MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { // ----------- S t a t e ------------- // -- lr : return address // -- r0 : key // -- r1 : receiver // ----------------------------------- + Label miss; + + __ IncrementCounter(&Counters::keyed_load_function_prototype, 1, r2, r3); + + // Check the name hasn't changed. + __ cmp(r0, Operand(Handle(name))); + __ b(ne, &miss); + + GenerateLoadFunctionPrototype(masm(), r1, r2, r3, &miss); + __ bind(&miss); + __ DecrementCounter(&Counters::keyed_load_function_prototype, 1, r2, r3); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); return GetCode(CALLBACKS, name); diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index b2ebece9c1..5ecf5e303b 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -364,6 +364,10 @@ function ArrayJoin(separator) { } else if (!IS_STRING(separator)) { separator = ToString(separator); } + + var result = %_FastAsciiArrayJoin(this, separator); + if (typeof result != "undefined") return result; + var length = TO_UINT32(this.length); return Join(this, length, separator, ConvertToString); } diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index 04c2977570..0846dbc537 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -1416,7 +1416,8 @@ class FunctionLiteral: public Expression { contains_loops_(contains_loops), function_token_position_(RelocInfo::kNoPosition), inferred_name_(Heap::empty_string()), - try_full_codegen_(false) { + try_full_codegen_(false), + pretenure_(false) { #ifdef DEBUG already_compiled_ = false; #endif @@ -1459,6 +1460,9 @@ class FunctionLiteral: public Expression { bool try_full_codegen() { return try_full_codegen_; } void set_try_full_codegen(bool flag) { try_full_codegen_ = flag; } + bool pretenure() { return pretenure_; } + void set_pretenure(bool value) { pretenure_ = value; } + #ifdef DEBUG void mark_as_compiled() { ASSERT(!already_compiled_); @@ -1482,6 +1486,7 @@ class FunctionLiteral: public Expression { int function_token_position_; Handle inferred_name_; bool try_full_codegen_; + bool pretenure_; #ifdef DEBUG bool already_compiled_; #endif diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index aede302035..e88ef6f0e1 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -1081,29 +1081,22 @@ BUILTIN(FastHandleApiCall) { ASSERT(!CalledAsConstructor()); const bool is_construct = false; - // We expect four more arguments: function, callback, call data, and holder. + // We expect four more arguments: callback, function, call data, and holder. const int args_length = args.length() - 4; ASSERT(args_length >= 0); - Handle function = args.at(args_length); - Object* callback_obj = args[args_length + 1]; - Handle data = args.at(args_length + 2); - Handle checked_holder = args.at(args_length + 3); - -#ifdef DEBUG - VerifyTypeCheck(checked_holder, function); -#endif - - CustomArguments custom; - v8::ImplementationUtilities::PrepareArgumentsData(custom.end(), - *data, *function, *checked_holder); + Object* callback_obj = args[args_length]; v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( - custom.end(), + &args[args_length + 1], &args[0] - 1, args_length - 1, is_construct); +#ifdef DEBUG + VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()), + Utils::OpenHandle(*new_args.Callee())); +#endif HandleScope scope; Object* result; v8::Handle value; diff --git a/deps/v8/src/conversions.cc b/deps/v8/src/conversions.cc index c0dbf73ad0..19fa7773ab 100644 --- a/deps/v8/src/conversions.cc +++ b/deps/v8/src/conversions.cc @@ -39,16 +39,6 @@ namespace v8 { namespace internal { -int HexValue(uc32 c) { - if ('0' <= c && c <= '9') - return c - '0'; - if ('a' <= c && c <= 'f') - return c - 'a' + 10; - if ('A' <= c && c <= 'F') - return c - 'A' + 10; - return -1; -} - namespace { // C++-style iterator adaptor for StringInputBuffer diff --git a/deps/v8/src/conversions.h b/deps/v8/src/conversions.h index 9e32a0cdb5..312e6aee54 100644 --- a/deps/v8/src/conversions.h +++ b/deps/v8/src/conversions.h @@ -75,11 +75,6 @@ static inline uint32_t DoubleToUint32(double x) { } -// Returns the value (0 .. 15) of a hexadecimal character c. -// If c is not a legal hexadecimal character, returns a value < 0. -int HexValue(uc32 c); - - // Enumeration for allowing octals and ignoring junk when converting // strings to numbers. enum ConversionFlags { diff --git a/deps/v8/src/dtoa-config.c b/deps/v8/src/dtoa-config.c deleted file mode 100644 index 9c5ee33194..0000000000 --- a/deps/v8/src/dtoa-config.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2007-2008 the V8 project authors. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * Dtoa needs to have a particular environment set up for it so - * instead of using it directly you should use this file. - * - * The way it works is that when you link with it, its definitions - * of dtoa, strtod etc. override the default ones. So if you fail - * to link with this library everything will still work, it's just - * subtly wrong. - */ - -#if !(defined(__APPLE__) && defined(__MACH__)) && \ - !defined(WIN32) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && \ - !defined(__sun) -#include -#endif -#include -#include - -/* The floating point word order on ARM is big endian when floating point - * emulation is used, even if the byte order is little endian */ -#if !(defined(__APPLE__) && defined(__MACH__)) && !defined(WIN32) && \ - !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sun) && \ - __FLOAT_WORD_ORDER == __BIG_ENDIAN -#define IEEE_MC68k -#else -#define IEEE_8087 -#endif - -#define __MATH_H__ -#if defined(__APPLE__) && defined(__MACH__) || defined(__FreeBSD__) || \ - defined(__OpenBSD__) || defined(__sun) -/* stdlib.h on FreeBSD and Apple's 10.5 and later SDKs will mangle the - * name of strtod. If it's included after strtod is redefined as - * gay_strtod, it will mangle the name of gay_strtod, which is - * unwanted. */ -#include - -#endif -/* stdlib.h on Windows adds __declspec(dllimport) to all functions when using - * the DLL version of the CRT (compiling with /MD or /MDd). If stdlib.h is - * included after strtod is redefined as gay_strtod, it will add - * __declspec(dllimport) to gay_strtod, which causes the compilation of - * gay_strtod in dtoa.c to fail. -*/ -#if defined(WIN32) && defined(_DLL) -#include "stdlib.h" -#endif - -/* For MinGW, turn on __NO_ISOCEXT so that its strtod doesn't get added */ -#ifdef __MINGW32__ -#define __NO_ISOCEXT -#endif /* __MINGW32__ */ - -/* On 64-bit systems, we need to make sure that a Long is only 32 bits. */ -#ifdef V8_TARGET_ARCH_X64 -#define Long int -#endif /* V8_TARGET_ARCH_X64 */ - -/* Make sure we use the David M. Gay version of strtod(). On Linux, we - * cannot use the same name (maybe the function does not have weak - * linkage?). */ -#define strtod gay_strtod -#include "third_party/dtoa/dtoa.c" diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc index 8592472524..a890f15974 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -882,12 +882,12 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { Visit(stmt->body()); // Check stack before looping. + __ bind(loop_statement.continue_target()); __ StackLimitCheck(&stack_limit_hit); __ bind(&stack_check_success); // Record the position of the do while condition and make sure it is // possible to break on the condition. - __ bind(loop_statement.continue_target()); SetExpressionPosition(stmt->cond(), stmt->condition_position()); VisitForControl(stmt->cond(), &body, @@ -1168,14 +1168,14 @@ void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { SetStackOverflow(); return; } - EmitNewClosure(function_info); + EmitNewClosure(function_info, expr->pretenure()); } void FullCodeGenerator::VisitSharedFunctionInfoLiteral( SharedFunctionInfoLiteral* expr) { Comment cmnt(masm_, "[ SharedFunctionInfoLiteral"); - EmitNewClosure(expr->shared_function_info()); + EmitNewClosure(expr->shared_function_info(), false); } diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h index 6a1def6ee1..97a56bd908 100644 --- a/deps/v8/src/full-codegen.h +++ b/deps/v8/src/full-codegen.h @@ -348,7 +348,7 @@ class FullCodeGenerator: public AstVisitor { // Platform-specific support for allocating a new closure based on // the given function info. - void EmitNewClosure(Handle info); + void EmitNewClosure(Handle info, bool pretenure); // Platform-specific support for compiling assignments. diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc index 1364951b71..3dfb886e99 100644 --- a/deps/v8/src/handles.cc +++ b/deps/v8/src/handles.cc @@ -37,6 +37,7 @@ #include "global-handles.h" #include "natives.h" #include "runtime.h" +#include "string-search.h" #include "stub-cache.h" namespace v8 { @@ -508,43 +509,50 @@ void InitScriptLineEnds(Handle