diff options
Diffstat (limited to 'deps/v8/src/x87/code-stubs-x87.cc')
-rw-r--r-- | deps/v8/src/x87/code-stubs-x87.cc | 1384 |
1 files changed, 810 insertions, 574 deletions
diff --git a/deps/v8/src/x87/code-stubs-x87.cc b/deps/v8/src/x87/code-stubs-x87.cc index 1da5f41a88..e1ad6a7f5a 100644 --- a/deps/v8/src/x87/code-stubs-x87.cc +++ b/deps/v8/src/x87/code-stubs-x87.cc @@ -327,7 +327,6 @@ void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, void MathPowStub::Generate(MacroAssembler* masm) { const Register base = edx; const Register scratch = ecx; - Counters* counters = isolate()->counters(); Label call_runtime; // We will call runtime helper function directly. @@ -340,7 +339,6 @@ void MathPowStub::Generate(MacroAssembler* masm) { // as heap number in exponent. __ AllocateHeapNumber(eax, scratch, base, &call_runtime); __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); - __ IncrementCounter(counters->math_pow(), 1); __ ret(2 * kPointerSize); } else { // Currently it's only called from full-compiler and exponent type is @@ -431,456 +429,6 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) { } -void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { - // The key is in edx and the parameter count is in eax. - DCHECK(edx.is(ArgumentsAccessReadDescriptor::index())); - DCHECK(eax.is(ArgumentsAccessReadDescriptor::parameter_count())); - - // The displacement is used for skipping the frame pointer on the - // stack. It is the offset of the last parameter (if any) relative - // to the frame pointer. - static const int kDisplacement = 1 * kPointerSize; - - // Check that the key is a smi. - Label slow; - __ JumpIfNotSmi(edx, &slow, Label::kNear); - - // Check if the calling frame is an arguments adaptor frame. - Label adaptor; - __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); - __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset)); - __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); - __ j(equal, &adaptor, Label::kNear); - - // Check index against formal parameters count limit passed in - // through register eax. Use unsigned comparison to get negative - // check for free. - __ cmp(edx, eax); - __ j(above_equal, &slow, Label::kNear); - - // Read the argument from the stack and return it. - STATIC_ASSERT(kSmiTagSize == 1); - STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. - __ lea(ebx, Operand(ebp, eax, times_2, 0)); - __ neg(edx); - __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); - __ ret(0); - - // Arguments adaptor case: Check index against actual arguments - // limit found in the arguments adaptor frame. Use unsigned - // comparison to get negative check for free. - __ bind(&adaptor); - __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); - __ cmp(edx, ecx); - __ j(above_equal, &slow, Label::kNear); - - // Read the argument from the stack and return it. - STATIC_ASSERT(kSmiTagSize == 1); - STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. - __ lea(ebx, Operand(ebx, ecx, times_2, 0)); - __ neg(edx); - __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); - __ ret(0); - - // Slow-case: Handle non-smi or out-of-bounds access to arguments - // by calling the runtime system. - __ bind(&slow); - __ pop(ebx); // Return address. - __ push(edx); - __ push(ebx); - __ TailCallRuntime(Runtime::kArguments); -} - - -void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) { - // ecx : number of parameters (tagged) - // edx : parameters pointer - // edi : function - // esp[0] : return address - - DCHECK(edi.is(ArgumentsAccessNewDescriptor::function())); - DCHECK(ecx.is(ArgumentsAccessNewDescriptor::parameter_count())); - DCHECK(edx.is(ArgumentsAccessNewDescriptor::parameter_pointer())); - - // Check if the calling frame is an arguments adaptor frame. - Label runtime; - __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); - __ mov(eax, Operand(ebx, StandardFrameConstants::kContextOffset)); - __ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); - __ j(not_equal, &runtime, Label::kNear); - - // Patch the arguments.length and the parameters pointer. - __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); - __ lea(edx, - Operand(ebx, ecx, times_2, StandardFrameConstants::kCallerSPOffset)); - - __ bind(&runtime); - __ pop(eax); // Pop return address. - __ push(edi); // Push function. - __ push(edx); // Push parameters pointer. - __ push(ecx); // Push parameter count. - __ push(eax); // Push return address. - __ TailCallRuntime(Runtime::kNewSloppyArguments); -} - - -void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) { - // ecx : number of parameters (tagged) - // edx : parameters pointer - // edi : function - // esp[0] : return address - - DCHECK(edi.is(ArgumentsAccessNewDescriptor::function())); - DCHECK(ecx.is(ArgumentsAccessNewDescriptor::parameter_count())); - DCHECK(edx.is(ArgumentsAccessNewDescriptor::parameter_pointer())); - - // Check if the calling frame is an arguments adaptor frame. - Label adaptor_frame, try_allocate, runtime; - __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); - __ mov(eax, Operand(ebx, StandardFrameConstants::kContextOffset)); - __ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); - __ j(equal, &adaptor_frame, Label::kNear); - - // No adaptor, parameter count = argument count. - __ mov(ebx, ecx); - __ push(ecx); - __ jmp(&try_allocate, Label::kNear); - - // We have an adaptor frame. Patch the parameters pointer. - __ bind(&adaptor_frame); - __ mov(ebx, ecx); - __ push(ecx); - __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); - __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); - __ lea(edx, Operand(edx, ecx, times_2, - StandardFrameConstants::kCallerSPOffset)); - - // ebx = parameter count (tagged) - // ecx = argument count (smi-tagged) - // Compute the mapped parameter count = min(ebx, ecx) in ebx. - __ cmp(ebx, ecx); - __ j(less_equal, &try_allocate, Label::kNear); - __ mov(ebx, ecx); - - // Save mapped parameter count and function. - __ bind(&try_allocate); - __ push(edi); - __ push(ebx); - - // Compute the sizes of backing store, parameter map, and arguments object. - // 1. Parameter map, has 2 extra words containing context and backing store. - const int kParameterMapHeaderSize = - FixedArray::kHeaderSize + 2 * kPointerSize; - Label no_parameter_map; - __ test(ebx, ebx); - __ j(zero, &no_parameter_map, Label::kNear); - __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); - __ bind(&no_parameter_map); - - // 2. Backing store. - __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); - - // 3. Arguments object. - __ add(ebx, Immediate(Heap::kSloppyArgumentsObjectSize)); - - // Do the allocation of all three objects in one go. - __ Allocate(ebx, eax, edi, no_reg, &runtime, TAG_OBJECT); - - // eax = address of new object(s) (tagged) - // ecx = argument count (smi-tagged) - // esp[0] = mapped parameter count (tagged) - // esp[4] = function - // esp[8] = parameter count (tagged) - // Get the arguments map from the current native context into edi. - Label has_mapped_parameters, instantiate; - __ mov(edi, NativeContextOperand()); - __ mov(ebx, Operand(esp, 0 * kPointerSize)); - __ test(ebx, ebx); - __ j(not_zero, &has_mapped_parameters, Label::kNear); - __ mov( - edi, - Operand(edi, Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX))); - __ jmp(&instantiate, Label::kNear); - - __ bind(&has_mapped_parameters); - __ mov(edi, Operand(edi, Context::SlotOffset( - Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX))); - __ bind(&instantiate); - - // eax = address of new object (tagged) - // ebx = mapped parameter count (tagged) - // ecx = argument count (smi-tagged) - // edi = address of arguments map (tagged) - // esp[0] = mapped parameter count (tagged) - // esp[4] = function - // esp[8] = parameter count (tagged) - // Copy the JS object part. - __ mov(FieldOperand(eax, JSObject::kMapOffset), edi); - __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), - masm->isolate()->factory()->empty_fixed_array()); - __ mov(FieldOperand(eax, JSObject::kElementsOffset), - masm->isolate()->factory()->empty_fixed_array()); - - // Set up the callee in-object property. - STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); - __ mov(edi, Operand(esp, 1 * kPointerSize)); - __ AssertNotSmi(edi); - __ mov(FieldOperand(eax, JSObject::kHeaderSize + - Heap::kArgumentsCalleeIndex * kPointerSize), - edi); - - // Use the length (smi tagged) and set that as an in-object property too. - __ AssertSmi(ecx); - STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); - __ mov(FieldOperand(eax, JSObject::kHeaderSize + - Heap::kArgumentsLengthIndex * kPointerSize), - ecx); - - // Set up the elements pointer in the allocated arguments object. - // If we allocated a parameter map, edi will point there, otherwise to the - // backing store. - __ lea(edi, Operand(eax, Heap::kSloppyArgumentsObjectSize)); - __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); - - // eax = address of new object (tagged) - // ebx = mapped parameter count (tagged) - // ecx = argument count (tagged) - // edx = address of receiver argument - // edi = address of parameter map or backing store (tagged) - // esp[0] = mapped parameter count (tagged) - // esp[4] = function - // esp[8] = parameter count (tagged) - // Free two registers. - __ push(edx); - __ push(eax); - - // Initialize parameter map. If there are no mapped arguments, we're done. - Label skip_parameter_map; - __ test(ebx, ebx); - __ j(zero, &skip_parameter_map); - - __ mov(FieldOperand(edi, FixedArray::kMapOffset), - Immediate(isolate()->factory()->sloppy_arguments_elements_map())); - __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2)))); - __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); - __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); - __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); - __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); - - // Copy the parameter slots and the holes in the arguments. - // We need to fill in mapped_parameter_count slots. They index the context, - // where parameters are stored in reverse order, at - // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 - // The mapped parameter thus need to get indices - // MIN_CONTEXT_SLOTS+parameter_count-1 .. - // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count - // We loop from right to left. - Label parameters_loop, parameters_test; - __ push(ecx); - __ mov(eax, Operand(esp, 3 * kPointerSize)); - __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); - __ add(ebx, Operand(esp, 5 * kPointerSize)); - __ sub(ebx, eax); - __ mov(ecx, isolate()->factory()->the_hole_value()); - __ mov(edx, edi); - __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); - // eax = loop variable (tagged) - // ebx = mapping index (tagged) - // ecx = the hole value - // edx = address of parameter map (tagged) - // edi = address of backing store (tagged) - // esp[0] = argument count (tagged) - // esp[4] = address of new object (tagged) - // esp[8] = address of receiver argument - // esp[12] = mapped parameter count (tagged) - // esp[16] = function - // esp[20] = parameter count (tagged) - __ jmp(¶meters_test, Label::kNear); - - __ bind(¶meters_loop); - __ sub(eax, Immediate(Smi::FromInt(1))); - __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); - __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); - __ add(ebx, Immediate(Smi::FromInt(1))); - __ bind(¶meters_test); - __ test(eax, eax); - __ j(not_zero, ¶meters_loop, Label::kNear); - __ pop(ecx); - - __ bind(&skip_parameter_map); - - // ecx = argument count (tagged) - // edi = address of backing store (tagged) - // esp[0] = address of new object (tagged) - // esp[4] = address of receiver argument - // esp[8] = mapped parameter count (tagged) - // esp[12] = function - // esp[16] = parameter count (tagged) - // Copy arguments header and remaining slots (if there are any). - __ mov(FieldOperand(edi, FixedArray::kMapOffset), - Immediate(isolate()->factory()->fixed_array_map())); - __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); - - Label arguments_loop, arguments_test; - __ mov(ebx, Operand(esp, 2 * kPointerSize)); - __ mov(edx, Operand(esp, 1 * kPointerSize)); - __ sub(edx, ebx); // Is there a smarter way to do negative scaling? - __ sub(edx, ebx); - __ jmp(&arguments_test, Label::kNear); - - __ bind(&arguments_loop); - __ sub(edx, Immediate(kPointerSize)); - __ mov(eax, Operand(edx, 0)); - __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); - __ add(ebx, Immediate(Smi::FromInt(1))); - - __ bind(&arguments_test); - __ cmp(ebx, ecx); - __ j(less, &arguments_loop, Label::kNear); - - // Restore. - __ pop(eax); // Address of arguments object. - __ Drop(4); - - // Return. - __ ret(0); - - // Do the runtime call to allocate the arguments object. - __ bind(&runtime); - __ pop(eax); // Remove saved mapped parameter count. - __ pop(edi); // Pop saved function. - __ pop(eax); // Remove saved parameter count. - __ pop(eax); // Pop return address. - __ push(edi); // Push function. - __ push(edx); // Push parameters pointer. - __ push(ecx); // Push parameter count. - __ push(eax); // Push return address. - __ TailCallRuntime(Runtime::kNewSloppyArguments); -} - - -void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { - // ecx : number of parameters (tagged) - // edx : parameters pointer - // edi : function - // esp[0] : return address - - DCHECK(edi.is(ArgumentsAccessNewDescriptor::function())); - DCHECK(ecx.is(ArgumentsAccessNewDescriptor::parameter_count())); - DCHECK(edx.is(ArgumentsAccessNewDescriptor::parameter_pointer())); - - // Check if the calling frame is an arguments adaptor frame. - Label try_allocate, runtime; - __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); - __ mov(eax, Operand(ebx, StandardFrameConstants::kContextOffset)); - __ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); - __ j(not_equal, &try_allocate, Label::kNear); - - // Patch the arguments.length and the parameters pointer. - __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); - __ lea(edx, - Operand(ebx, ecx, times_2, StandardFrameConstants::kCallerSPOffset)); - - // Try the new space allocation. Start out with computing the size of - // the arguments object and the elements array. - Label add_arguments_object; - __ bind(&try_allocate); - __ mov(eax, ecx); - __ test(eax, eax); - __ j(zero, &add_arguments_object, Label::kNear); - __ lea(eax, Operand(eax, times_2, FixedArray::kHeaderSize)); - __ bind(&add_arguments_object); - __ add(eax, Immediate(Heap::kStrictArgumentsObjectSize)); - - // Do the allocation of both objects in one go. - __ Allocate(eax, eax, ebx, no_reg, &runtime, TAG_OBJECT); - - // Get the arguments map from the current native context. - __ mov(edi, NativeContextOperand()); - __ mov(edi, ContextOperand(edi, Context::STRICT_ARGUMENTS_MAP_INDEX)); - - __ mov(FieldOperand(eax, JSObject::kMapOffset), edi); - __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), - masm->isolate()->factory()->empty_fixed_array()); - __ mov(FieldOperand(eax, JSObject::kElementsOffset), - masm->isolate()->factory()->empty_fixed_array()); - - // Get the length (smi tagged) and set that as an in-object property too. - STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); - __ AssertSmi(ecx); - __ mov(FieldOperand(eax, JSObject::kHeaderSize + - Heap::kArgumentsLengthIndex * kPointerSize), - ecx); - - // If there are no actual arguments, we're done. - Label done; - __ test(ecx, ecx); - __ j(zero, &done, Label::kNear); - - // Set up the elements pointer in the allocated arguments object and - // initialize the header in the elements fixed array. - __ lea(edi, Operand(eax, Heap::kStrictArgumentsObjectSize)); - __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); - __ mov(FieldOperand(edi, FixedArray::kMapOffset), - Immediate(isolate()->factory()->fixed_array_map())); - __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); - - // Untag the length for the loop below. - __ SmiUntag(ecx); - - // Copy the fixed array slots. - Label loop; - __ bind(&loop); - __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver. - __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); - __ add(edi, Immediate(kPointerSize)); - __ sub(edx, Immediate(kPointerSize)); - __ dec(ecx); - __ j(not_zero, &loop); - - // Return. - __ bind(&done); - __ ret(0); - - // Do the runtime call to allocate the arguments object. - __ bind(&runtime); - __ pop(eax); // Pop return address. - __ push(edi); // Push function. - __ push(edx); // Push parameters pointer. - __ push(ecx); // Push parameter count. - __ push(eax); // Push return address. - __ TailCallRuntime(Runtime::kNewStrictArguments); -} - - -void RestParamAccessStub::GenerateNew(MacroAssembler* masm) { - // ecx : number of parameters (tagged) - // edx : parameters pointer - // ebx : rest parameter index (tagged) - // esp[0] : return address - - // Check if the calling frame is an arguments adaptor frame. - Label runtime; - __ mov(edi, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); - __ mov(eax, Operand(edi, StandardFrameConstants::kContextOffset)); - __ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); - __ j(not_equal, &runtime); - - // Patch the arguments.length and the parameters pointer. - __ mov(ecx, Operand(edi, ArgumentsAdaptorFrameConstants::kLengthOffset)); - __ lea(edx, - Operand(edi, ecx, times_2, StandardFrameConstants::kCallerSPOffset)); - - __ bind(&runtime); - __ pop(eax); // Save return address. - __ push(ecx); // Push number of parameters. - __ push(edx); // Push parameters pointer. - __ push(ebx); // Push rest parameter index. - __ push(eax); // Push return address. - __ TailCallRuntime(Runtime::kNewRestParam); -} - - void RegExpExecStub::Generate(MacroAssembler* masm) { // Just jump directly to runtime if native RegExp is not selected at compile // time or if regexp entry in generated code is turned off runtime switch or @@ -1384,16 +932,11 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { // Check for undefined. undefined OP undefined is false even though // undefined == undefined. __ cmp(edx, isolate()->factory()->undefined_value()); - if (is_strong(strength())) { - // In strong mode, this comparison must throw, so call the runtime. - __ j(equal, &runtime_call, Label::kFar); - } else { - Label check_for_nan; - __ j(not_equal, &check_for_nan, Label::kNear); - __ Move(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc)))); - __ ret(0); - __ bind(&check_for_nan); - } + Label check_for_nan; + __ j(not_equal, &check_for_nan, Label::kNear); + __ Move(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc)))); + __ ret(0); + __ bind(&check_for_nan); } // Test for NaN. Compare heap numbers in a general way, @@ -1413,12 +956,6 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { // Call runtime on identical SIMD values since we must throw a TypeError. __ cmpb(ecx, static_cast<uint8_t>(SIMD128_VALUE_TYPE)); __ j(equal, &runtime_call, Label::kFar); - if (is_strong(strength())) { - // We have already tested for smis and heap numbers, so if both - // arguments are not strings we must proceed to the slow case. - __ test(ecx, Immediate(kIsNotStringMask)); - __ j(not_zero, &runtime_call, Label::kFar); - } } __ Move(eax, Immediate(Smi::FromInt(EQUAL))); __ ret(0); @@ -1575,7 +1112,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { // Non-strict equality. Objects are unequal if // they are both JSObjects and not undetectable, // and their pointers are different. - Label return_unequal; + Label return_unequal, undetectable; // At most one is a smi, so we can test for smi by adding the two. // A smi plus a heap object has the low bit set, a heap object plus // a heap object has the low bit clear. @@ -1584,26 +1121,32 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { __ lea(ecx, Operand(eax, edx, times_1, 0)); __ test(ecx, Immediate(kSmiTagMask)); __ j(not_zero, &runtime_call, Label::kNear); - __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx); + + __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); + __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); + + __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), + 1 << Map::kIsUndetectable); + __ j(not_zero, &undetectable, Label::kNear); + __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), + 1 << Map::kIsUndetectable); + __ j(not_zero, &return_unequal, Label::kNear); + + __ CmpInstanceType(ebx, FIRST_JS_RECEIVER_TYPE); __ j(below, &runtime_call, Label::kNear); - __ CmpObjectType(edx, FIRST_JS_RECEIVER_TYPE, ebx); + __ CmpInstanceType(ecx, FIRST_JS_RECEIVER_TYPE); __ j(below, &runtime_call, Label::kNear); - // We do not bail out after this point. Both are JSObjects, and - // they are equal if and only if both are undetectable. - // The and of the undetectable flags is 1 if and only if they are equal. + + __ bind(&return_unequal); + // Return non-equal by returning the non-zero object pointer in eax. + __ ret(0); // eax, edx were pushed + + __ bind(&undetectable); __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsUndetectable); __ j(zero, &return_unequal, Label::kNear); - __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), - 1 << Map::kIsUndetectable); - __ j(zero, &return_unequal, Label::kNear); - // The objects are both undetectable, so they both compare as the value - // undefined, and are equal. __ Move(eax, Immediate(EQUAL)); - __ bind(&return_unequal); - // Return non-equal by returning the non-zero object pointer in eax, - // or return equal if we fell through to here. - __ ret(0); // rax, rdx were pushed + __ ret(0); // eax, edx were pushed } __ bind(&runtime_call); @@ -1624,8 +1167,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) // tagged as a small integer. - __ TailCallRuntime(is_strong(strength()) ? Runtime::kCompare_Strong - : Runtime::kCompare); + __ TailCallRuntime(Runtime::kCompare); } __ bind(&miss); @@ -1854,7 +1396,8 @@ void CallICStub::Generate(MacroAssembler* masm) { __ bind(&call_function); __ Set(eax, argc); - __ Jump(masm->isolate()->builtins()->CallFunction(convert_mode()), + __ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(), + tail_call_mode()), RelocInfo::CODE_TARGET); __ bind(&extra_checks_or_miss); @@ -1893,7 +1436,7 @@ void CallICStub::Generate(MacroAssembler* masm) { __ bind(&call); __ Set(eax, argc); - __ Jump(masm->isolate()->builtins()->Call(convert_mode()), + __ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()), RelocInfo::CODE_TARGET); __ bind(&uninitialized); @@ -2015,16 +1558,22 @@ void CEntryStub::Generate(MacroAssembler* masm) { ProfileEntryHookStub::MaybeCallEntryHook(masm); + // Reserve space on the stack for the three arguments passed to the call. If + // result size is greater than can be returned in registers, also reserve + // space for the hidden argument for the result location, and space for the + // result itself. + int arg_stack_space = result_size() < 3 ? 3 : 4 + result_size(); + // Enter the exit frame that transitions from JavaScript to C++. if (argv_in_register()) { DCHECK(!save_doubles()); - __ EnterApiExitFrame(3); + __ EnterApiExitFrame(arg_stack_space); // Move argc and argv into the correct registers. __ mov(esi, ecx); __ mov(edi, eax); } else { - __ EnterExitFrame(save_doubles()); + __ EnterExitFrame(arg_stack_space, save_doubles()); } // ebx: pointer to C function (C callee-saved) @@ -2039,14 +1588,36 @@ void CEntryStub::Generate(MacroAssembler* masm) { if (FLAG_debug_code) { __ CheckStackAlignment(); } - // Call C function. - __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. - __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. - __ mov(Operand(esp, 2 * kPointerSize), - Immediate(ExternalReference::isolate_address(isolate()))); + if (result_size() <= 2) { + __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. + __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. + __ mov(Operand(esp, 2 * kPointerSize), + Immediate(ExternalReference::isolate_address(isolate()))); + } else { + DCHECK_EQ(3, result_size()); + // Pass a pointer to the result location as the first argument. + __ lea(eax, Operand(esp, 4 * kPointerSize)); + __ mov(Operand(esp, 0 * kPointerSize), eax); + __ mov(Operand(esp, 1 * kPointerSize), edi); // argc. + __ mov(Operand(esp, 2 * kPointerSize), esi); // argv. + __ mov(Operand(esp, 3 * kPointerSize), + Immediate(ExternalReference::isolate_address(isolate()))); + } __ call(ebx); - // Result is in eax or edx:eax - do not destroy these registers! + + if (result_size() > 2) { + DCHECK_EQ(3, result_size()); +#ifndef _WIN32 + // Restore the "hidden" argument on the stack which was popped by caller. + __ sub(esp, Immediate(kPointerSize)); +#endif + // Read result values stored on stack. Result is stored above the arguments. + __ mov(kReturnRegister0, Operand(esp, 4 * kPointerSize)); + __ mov(kReturnRegister1, Operand(esp, 5 * kPointerSize)); + __ mov(kReturnRegister2, Operand(esp, 6 * kPointerSize)); + } + // Result is in eax, edx:eax or edi:edx:eax - do not destroy these registers! // Check result for exception sentinel. Label exception_returned; @@ -2117,6 +1688,16 @@ void CEntryStub::Generate(MacroAssembler* masm) { // Compute the handler entry address and jump to it. __ mov(edi, Operand::StaticVariable(pending_handler_code_address)); __ mov(edx, Operand::StaticVariable(pending_handler_offset_address)); + // Check whether it's a turbofanned exception handler code before jump to it. + Label not_turbo; + __ push(eax); + __ mov(eax, Operand(edi, Code::kKindSpecificFlags1Offset - kHeapObjectTag)); + __ and_(eax, Immediate(1 << Code::kIsTurbofannedBit)); + __ j(zero, ¬_turbo); + __ fninit(); + __ fld1(); + __ bind(¬_turbo); + __ pop(eax); __ lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize)); __ jmp(edi); } @@ -2840,6 +2421,42 @@ void ToStringStub::Generate(MacroAssembler* masm) { } +void ToNameStub::Generate(MacroAssembler* masm) { + // The ToName stub takes one argument in eax. + Label is_number; + __ JumpIfSmi(eax, &is_number, Label::kNear); + + Label not_name; + STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); + __ CmpObjectType(eax, LAST_NAME_TYPE, edi); + // eax: receiver + // edi: receiver map + __ j(above, ¬_name, Label::kNear); + __ Ret(); + __ bind(¬_name); + + Label not_heap_number; + __ CompareMap(eax, masm->isolate()->factory()->heap_number_map()); + __ j(not_equal, ¬_heap_number, Label::kNear); + __ bind(&is_number); + NumberToStringStub stub(isolate()); + __ TailCallStub(&stub); + __ bind(¬_heap_number); + + Label not_oddball; + __ CmpInstanceType(edi, ODDBALL_TYPE); + __ j(not_equal, ¬_oddball, Label::kNear); + __ mov(eax, FieldOperand(eax, Oddball::kToStringOffset)); + __ Ret(); + __ bind(¬_oddball); + + __ pop(ecx); // Pop return address. + __ push(eax); // Push argument. + __ push(ecx); // Push return address. + __ TailCallRuntime(Runtime::kToName); +} + + void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm, Register left, Register right, @@ -3043,19 +2660,15 @@ void CompareICStub::GenerateBooleans(MacroAssembler* masm) { __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); __ JumpIfNotRoot(ecx, Heap::kBooleanMapRootIndex, &miss, miss_distance); __ JumpIfNotRoot(ebx, Heap::kBooleanMapRootIndex, &miss, miss_distance); - if (op() != Token::EQ_STRICT && is_strong(strength())) { - __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion); - } else { - if (!Token::IsEqualityOp(op())) { - __ mov(eax, FieldOperand(eax, Oddball::kToNumberOffset)); - __ AssertSmi(eax); - __ mov(edx, FieldOperand(edx, Oddball::kToNumberOffset)); - __ AssertSmi(edx); - __ xchg(eax, edx); - } - __ sub(eax, edx); - __ Ret(); + if (!Token::IsEqualityOp(op())) { + __ mov(eax, FieldOperand(eax, Oddball::kToNumberOffset)); + __ AssertSmi(eax); + __ mov(edx, FieldOperand(edx, Oddball::kToNumberOffset)); + __ AssertSmi(edx); + __ xchg(eax, edx); } + __ sub(eax, edx); + __ Ret(); __ bind(&miss); GenerateMiss(masm); @@ -3117,7 +2730,7 @@ void CompareICStub::GenerateNumbers(MacroAssembler* masm) { __ bind(&unordered); __ bind(&generic_stub); - CompareICStub stub(isolate(), op(), strength(), CompareICState::GENERIC, + CompareICStub stub(isolate(), op(), CompareICState::GENERIC, CompareICState::GENERIC, CompareICState::GENERIC); __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); @@ -3360,8 +2973,6 @@ void CompareICStub::GenerateKnownReceivers(MacroAssembler* masm) { if (Token::IsEqualityOp(op())) { __ sub(eax, edx); __ ret(0); - } else if (is_strong(strength())) { - __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion); } else { __ PopReturnAddressTo(ecx); __ Push(edx); @@ -3665,11 +3276,8 @@ void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { regs_.scratch0(), &dont_need_remembered_set); - __ CheckPageFlag(regs_.object(), - regs_.scratch0(), - 1 << MemoryChunk::SCAN_ON_SCAVENGE, - not_zero, - &dont_need_remembered_set); + __ JumpIfInNewSpace(regs_.object(), regs_.scratch0(), + &dont_need_remembered_set); // First notify the incremental marker if necessary, then update the // remembered set. @@ -4370,7 +3978,6 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm, __ jmp(&compare_map); } - void VectorKeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { Register receiver = VectorStoreICDescriptor::ReceiverRegister(); // edx Register key = VectorStoreICDescriptor::NameRegister(); // ecx @@ -4426,14 +4033,12 @@ void VectorKeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { KeyedStoreIC::GenerateMiss(masm); } - void CallICTrampolineStub::Generate(MacroAssembler* masm) { __ EmitLoadTypeFeedbackVector(ebx); CallICStub stub(isolate(), state()); __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); } - void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { if (masm->isolate()->function_entry_hook() != NULL) { ProfileEntryHookStub stub(masm->isolate()); @@ -4441,7 +4046,6 @@ void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { } } - void ProfileEntryHookStub::Generate(MacroAssembler* masm) { // Save volatile registers. const int kNumSavedRegisters = 3; @@ -4473,18 +4077,15 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) { __ ret(0); } - -template<class T> +template <class T> static void CreateArrayDispatch(MacroAssembler* masm, AllocationSiteOverrideMode mode) { if (mode == DISABLE_ALLOCATION_SITES) { - T stub(masm->isolate(), - GetInitialFastElementsKind(), - mode); + T stub(masm->isolate(), GetInitialFastElementsKind(), mode); __ TailCallStub(&stub); } else if (mode == DONT_OVERRIDE) { - int last_index = GetSequenceIndexFromFastElementsKind( - TERMINAL_FAST_ELEMENTS_KIND); + int last_index = + GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); for (int i = 0; i <= last_index; ++i) { Label next; ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); @@ -4502,7 +4103,6 @@ static void CreateArrayDispatch(MacroAssembler* masm, } } - static void CreateArrayDispatchOneArgument(MacroAssembler* masm, AllocationSiteOverrideMode mode) { // ebx - allocation site (if mode != DISABLE_ALLOCATION_SITES) @@ -4534,14 +4134,12 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm, ElementsKind initial = GetInitialFastElementsKind(); ElementsKind holey_initial = GetHoleyElementsKind(initial); - ArraySingleArgumentConstructorStub stub_holey(masm->isolate(), - holey_initial, - DISABLE_ALLOCATION_SITES); + ArraySingleArgumentConstructorStub stub_holey( + masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES); __ TailCallStub(&stub_holey); __ bind(&normal_sequence); - ArraySingleArgumentConstructorStub stub(masm->isolate(), - initial, + ArraySingleArgumentConstructorStub stub(masm->isolate(), initial, DISABLE_ALLOCATION_SITES); __ TailCallStub(&stub); } else if (mode == DONT_OVERRIDE) { @@ -4564,8 +4162,8 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm, Immediate(Smi::FromInt(kFastElementsKindPackedToHoley))); __ bind(&normal_sequence); - int last_index = GetSequenceIndexFromFastElementsKind( - TERMINAL_FAST_ELEMENTS_KIND); + int last_index = + GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); for (int i = 0; i <= last_index; ++i) { Label next; ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); @@ -4583,11 +4181,10 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm, } } - -template<class T> +template <class T> static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { - int to_index = GetSequenceIndexFromFastElementsKind( - TERMINAL_FAST_ELEMENTS_KIND); + int to_index = + GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); for (int i = 0; i <= to_index; ++i) { ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); T stub(isolate, kind); @@ -4599,7 +4196,6 @@ static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { } } - void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) { ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>( isolate); @@ -4609,10 +4205,9 @@ void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) { isolate); } - void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime( Isolate* isolate) { - ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS }; + ElementsKind kinds[2] = {FAST_ELEMENTS, FAST_HOLEY_ELEMENTS}; for (int i = 0; i < 2; i++) { // For internal arrays we only need a few things InternalArrayNoArgumentConstructorStub stubh1(isolate, kinds[i]); @@ -4624,10 +4219,8 @@ void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime( } } - void ArrayConstructorStub::GenerateDispatchToArrayStub( - MacroAssembler* masm, - AllocationSiteOverrideMode mode) { + MacroAssembler* masm, AllocationSiteOverrideMode mode) { if (argument_count() == ANY) { Label not_zero_case, not_one_case; __ test(eax, eax); @@ -4652,7 +4245,6 @@ void ArrayConstructorStub::GenerateDispatchToArrayStub( } } - void ArrayConstructorStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- eax : argc (only if argument_count() is ANY or MORE_THAN_ONE) @@ -4726,9 +4318,8 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ JumpToExternalReference(ExternalReference(Runtime::kNewArray, isolate())); } - -void InternalArrayConstructorStub::GenerateCase( - MacroAssembler* masm, ElementsKind kind) { +void InternalArrayConstructorStub::GenerateCase(MacroAssembler* masm, + ElementsKind kind) { Label not_zero_case, not_one_case; Label normal_sequence; @@ -4748,8 +4339,8 @@ void InternalArrayConstructorStub::GenerateCase( __ test(ecx, ecx); __ j(zero, &normal_sequence); - InternalArraySingleArgumentConstructorStub - stub1_holey(isolate(), GetHoleyElementsKind(kind)); + InternalArraySingleArgumentConstructorStub stub1_holey( + isolate(), GetHoleyElementsKind(kind)); __ TailCallStub(&stub1_holey); } @@ -4762,7 +4353,6 @@ void InternalArrayConstructorStub::GenerateCase( __ TailCallStub(&stubN); } - void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- eax : argc @@ -4798,8 +4388,7 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { __ cmp(ecx, Immediate(FAST_ELEMENTS)); __ j(equal, &done); __ cmp(ecx, Immediate(FAST_HOLEY_ELEMENTS)); - __ Assert(equal, - kInvalidElementsKindForInternalArrayOrInternalPackedArray); + __ Assert(equal, kInvalidElementsKindForInternalArrayOrInternalPackedArray); __ bind(&done); } @@ -4812,6 +4401,639 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { GenerateCase(masm, FAST_ELEMENTS); } +void FastNewObjectStub::Generate(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- edi : target + // -- edx : new target + // -- esi : context + // -- esp[0] : return address + // ----------------------------------- + __ AssertFunction(edi); + __ AssertReceiver(edx); + + // Verify that the new target is a JSFunction. + Label new_object; + __ CmpObjectType(edx, JS_FUNCTION_TYPE, ebx); + __ j(not_equal, &new_object); + + // Load the initial map and verify that it's in fact a map. + __ mov(ecx, FieldOperand(edx, JSFunction::kPrototypeOrInitialMapOffset)); + __ JumpIfSmi(ecx, &new_object); + __ CmpObjectType(ecx, MAP_TYPE, ebx); + __ j(not_equal, &new_object); + + // Fall back to runtime if the target differs from the new target's + // initial map constructor. + __ cmp(edi, FieldOperand(ecx, Map::kConstructorOrBackPointerOffset)); + __ j(not_equal, &new_object); + + // Allocate the JSObject on the heap. + Label allocate, done_allocate; + __ movzx_b(ebx, FieldOperand(ecx, Map::kInstanceSizeOffset)); + __ lea(ebx, Operand(ebx, times_pointer_size, 0)); + __ Allocate(ebx, eax, edi, no_reg, &allocate, NO_ALLOCATION_FLAGS); + __ bind(&done_allocate); + + // Initialize the JSObject fields. + __ mov(Operand(eax, JSObject::kMapOffset), ecx); + __ mov(Operand(eax, JSObject::kPropertiesOffset), + masm->isolate()->factory()->empty_fixed_array()); + __ mov(Operand(eax, JSObject::kElementsOffset), + masm->isolate()->factory()->empty_fixed_array()); + STATIC_ASSERT(JSObject::kHeaderSize == 3 * kPointerSize); + __ lea(ebx, Operand(eax, JSObject::kHeaderSize)); + + // ----------- S t a t e ------------- + // -- eax : result (untagged) + // -- ebx : result fields (untagged) + // -- edi : result end (untagged) + // -- ecx : initial map + // -- esi : context + // -- esp[0] : return address + // ----------------------------------- + + // Perform in-object slack tracking if requested. + Label slack_tracking; + STATIC_ASSERT(Map::kNoSlackTracking == 0); + __ test(FieldOperand(ecx, Map::kBitField3Offset), + Immediate(Map::ConstructionCounter::kMask)); + __ j(not_zero, &slack_tracking, Label::kNear); + { + // Initialize all in-object fields with undefined. + __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); + __ InitializeFieldsWithFiller(ebx, edi, edx); + + // Add the object tag to make the JSObject real. + STATIC_ASSERT(kHeapObjectTag == 1); + __ inc(eax); + __ Ret(); + } + __ bind(&slack_tracking); + { + // Decrease generous allocation count. + STATIC_ASSERT(Map::ConstructionCounter::kNext == 32); + __ sub(FieldOperand(ecx, Map::kBitField3Offset), + Immediate(1 << Map::ConstructionCounter::kShift)); + + // Initialize the in-object fields with undefined. + __ movzx_b(edx, FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset)); + __ neg(edx); + __ lea(edx, Operand(edi, edx, times_pointer_size, 0)); + __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); + __ InitializeFieldsWithFiller(ebx, edx, edi); + + // Initialize the remaining (reserved) fields with one pointer filler map. + __ movzx_b(edx, FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset)); + __ lea(edx, Operand(ebx, edx, times_pointer_size, 0)); + __ LoadRoot(edi, Heap::kOnePointerFillerMapRootIndex); + __ InitializeFieldsWithFiller(ebx, edx, edi); + + // Add the object tag to make the JSObject real. + STATIC_ASSERT(kHeapObjectTag == 1); + __ inc(eax); + + // Check if we can finalize the instance size. + Label finalize; + STATIC_ASSERT(Map::kSlackTrackingCounterEnd == 1); + __ test(FieldOperand(ecx, Map::kBitField3Offset), + Immediate(Map::ConstructionCounter::kMask)); + __ j(zero, &finalize, Label::kNear); + __ Ret(); + + // Finalize the instance size. + __ bind(&finalize); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ Push(eax); + __ Push(ecx); + __ CallRuntime(Runtime::kFinalizeInstanceSize); + __ Pop(eax); + } + __ Ret(); + } + + // Fall back to %AllocateInNewSpace. + __ bind(&allocate); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ SmiTag(ebx); + __ Push(ecx); + __ Push(ebx); + __ CallRuntime(Runtime::kAllocateInNewSpace); + __ Pop(ecx); + } + STATIC_ASSERT(kHeapObjectTag == 1); + __ dec(eax); + __ movzx_b(ebx, FieldOperand(ecx, Map::kInstanceSizeOffset)); + __ lea(edi, Operand(eax, ebx, times_pointer_size, 0)); + __ jmp(&done_allocate); + + // Fall back to %NewObject. + __ bind(&new_object); + __ PopReturnAddressTo(ecx); + __ Push(edi); + __ Push(edx); + __ PushReturnAddressFrom(ecx); + __ TailCallRuntime(Runtime::kNewObject); +} + +void FastNewRestParameterStub::Generate(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- edi : function + // -- esi : context + // -- ebp : frame pointer + // -- esp[0] : return address + // ----------------------------------- + __ AssertFunction(edi); + + // For Ignition we need to skip all possible handler/stub frames until + // we reach the JavaScript frame for the function (similar to what the + // runtime fallback implementation does). So make edx point to that + // JavaScript frame. + { + Label loop, loop_entry; + __ mov(edx, ebp); + __ jmp(&loop_entry, Label::kNear); + __ bind(&loop); + __ mov(edx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); + __ bind(&loop_entry); + __ cmp(edi, Operand(edx, StandardFrameConstants::kMarkerOffset)); + __ j(not_equal, &loop); + } + + // Check if we have rest parameters (only possible if we have an + // arguments adaptor frame below the function frame). + Label no_rest_parameters; + __ mov(ebx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); + __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset), + Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); + __ j(not_equal, &no_rest_parameters, Label::kNear); + + // Check if the arguments adaptor frame contains more arguments than + // specified by the function's internal formal parameter count. + Label rest_parameters; + __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); + __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); + __ sub(eax, + FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset)); + __ j(greater, &rest_parameters); + + // Return an empty rest parameter array. + __ bind(&no_rest_parameters); + { + // ----------- S t a t e ------------- + // -- esi : context + // -- esp[0] : return address + // ----------------------------------- + + // Allocate an empty rest parameter array. + Label allocate, done_allocate; + __ Allocate(JSArray::kSize, eax, edx, ecx, &allocate, TAG_OBJECT); + __ bind(&done_allocate); + + // Setup the rest parameter array in rax. + __ LoadGlobalFunction(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, ecx); + __ mov(FieldOperand(eax, JSArray::kMapOffset), ecx); + __ mov(ecx, isolate()->factory()->empty_fixed_array()); + __ mov(FieldOperand(eax, JSArray::kPropertiesOffset), ecx); + __ mov(FieldOperand(eax, JSArray::kElementsOffset), ecx); + __ mov(FieldOperand(eax, JSArray::kLengthOffset), + Immediate(Smi::FromInt(0))); + STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); + __ Ret(); + + // Fall back to %AllocateInNewSpace. + __ bind(&allocate); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ Push(Smi::FromInt(JSArray::kSize)); + __ CallRuntime(Runtime::kAllocateInNewSpace); + } + __ jmp(&done_allocate); + } + + __ bind(&rest_parameters); + { + // Compute the pointer to the first rest parameter (skippping the receiver). + __ lea(ebx, + Operand(ebx, eax, times_half_pointer_size, + StandardFrameConstants::kCallerSPOffset - 1 * kPointerSize)); + + // ----------- S t a t e ------------- + // -- esi : context + // -- eax : number of rest parameters (tagged) + // -- ebx : pointer to first rest parameters + // -- esp[0] : return address + // ----------------------------------- + + // Allocate space for the rest parameter array plus the backing store. + Label allocate, done_allocate; + __ lea(ecx, Operand(eax, times_half_pointer_size, + JSArray::kSize + FixedArray::kHeaderSize)); + __ Allocate(ecx, edx, edi, no_reg, &allocate, TAG_OBJECT); + __ bind(&done_allocate); + + // Setup the elements array in edx. + __ mov(FieldOperand(edx, FixedArray::kMapOffset), + isolate()->factory()->fixed_array_map()); + __ mov(FieldOperand(edx, FixedArray::kLengthOffset), eax); + { + Label loop, done_loop; + __ Move(ecx, Smi::FromInt(0)); + __ bind(&loop); + __ cmp(ecx, eax); + __ j(equal, &done_loop, Label::kNear); + __ mov(edi, Operand(ebx, 0 * kPointerSize)); + __ mov(FieldOperand(edx, ecx, times_half_pointer_size, + FixedArray::kHeaderSize), + edi); + __ sub(ebx, Immediate(1 * kPointerSize)); + __ add(ecx, Immediate(Smi::FromInt(1))); + __ jmp(&loop); + __ bind(&done_loop); + } + + // Setup the rest parameter array in edi. + __ lea(edi, + Operand(edx, eax, times_half_pointer_size, FixedArray::kHeaderSize)); + __ LoadGlobalFunction(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, ecx); + __ mov(FieldOperand(edi, JSArray::kMapOffset), ecx); + __ mov(FieldOperand(edi, JSArray::kPropertiesOffset), + isolate()->factory()->empty_fixed_array()); + __ mov(FieldOperand(edi, JSArray::kElementsOffset), edx); + __ mov(FieldOperand(edi, JSArray::kLengthOffset), eax); + STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); + __ mov(eax, edi); + __ Ret(); + + // Fall back to %AllocateInNewSpace. + __ bind(&allocate); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ SmiTag(ecx); + __ Push(eax); + __ Push(ebx); + __ Push(ecx); + __ CallRuntime(Runtime::kAllocateInNewSpace); + __ mov(edx, eax); + __ Pop(ebx); + __ Pop(eax); + } + __ jmp(&done_allocate); + } +} + +void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- edi : function + // -- esi : context + // -- ebp : frame pointer + // -- esp[0] : return address + // ----------------------------------- + __ AssertFunction(edi); + + // TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub. + __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); + __ mov(ecx, + FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset)); + __ lea(edx, Operand(ebp, ecx, times_half_pointer_size, + StandardFrameConstants::kCallerSPOffset)); + + // ecx : number of parameters (tagged) + // edx : parameters pointer + // edi : function + // esp[0] : return address + + // Check if the calling frame is an arguments adaptor frame. + Label adaptor_frame, try_allocate, runtime; + __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); + __ mov(eax, Operand(ebx, StandardFrameConstants::kContextOffset)); + __ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); + __ j(equal, &adaptor_frame, Label::kNear); + + // No adaptor, parameter count = argument count. + __ mov(ebx, ecx); + __ push(ecx); + __ jmp(&try_allocate, Label::kNear); + + // We have an adaptor frame. Patch the parameters pointer. + __ bind(&adaptor_frame); + __ mov(ebx, ecx); + __ push(ecx); + __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); + __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); + __ lea(edx, + Operand(edx, ecx, times_2, StandardFrameConstants::kCallerSPOffset)); + + // ebx = parameter count (tagged) + // ecx = argument count (smi-tagged) + // Compute the mapped parameter count = min(ebx, ecx) in ebx. + __ cmp(ebx, ecx); + __ j(less_equal, &try_allocate, Label::kNear); + __ mov(ebx, ecx); + + // Save mapped parameter count and function. + __ bind(&try_allocate); + __ push(edi); + __ push(ebx); + + // Compute the sizes of backing store, parameter map, and arguments object. + // 1. Parameter map, has 2 extra words containing context and backing store. + const int kParameterMapHeaderSize = + FixedArray::kHeaderSize + 2 * kPointerSize; + Label no_parameter_map; + __ test(ebx, ebx); + __ j(zero, &no_parameter_map, Label::kNear); + __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); + __ bind(&no_parameter_map); + + // 2. Backing store. + __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); + + // 3. Arguments object. + __ add(ebx, Immediate(JSSloppyArgumentsObject::kSize)); + + // Do the allocation of all three objects in one go. + __ Allocate(ebx, eax, edi, no_reg, &runtime, TAG_OBJECT); + + // eax = address of new object(s) (tagged) + // ecx = argument count (smi-tagged) + // esp[0] = mapped parameter count (tagged) + // esp[4] = function + // esp[8] = parameter count (tagged) + // Get the arguments map from the current native context into edi. + Label has_mapped_parameters, instantiate; + __ mov(edi, NativeContextOperand()); + __ mov(ebx, Operand(esp, 0 * kPointerSize)); + __ test(ebx, ebx); + __ j(not_zero, &has_mapped_parameters, Label::kNear); + __ mov( + edi, + Operand(edi, Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX))); + __ jmp(&instantiate, Label::kNear); + + __ bind(&has_mapped_parameters); + __ mov(edi, Operand(edi, Context::SlotOffset( + Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX))); + __ bind(&instantiate); + + // eax = address of new object (tagged) + // ebx = mapped parameter count (tagged) + // ecx = argument count (smi-tagged) + // edi = address of arguments map (tagged) + // esp[0] = mapped parameter count (tagged) + // esp[4] = function + // esp[8] = parameter count (tagged) + // Copy the JS object part. + __ mov(FieldOperand(eax, JSObject::kMapOffset), edi); + __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), + masm->isolate()->factory()->empty_fixed_array()); + __ mov(FieldOperand(eax, JSObject::kElementsOffset), + masm->isolate()->factory()->empty_fixed_array()); + + // Set up the callee in-object property. + STATIC_ASSERT(JSSloppyArgumentsObject::kCalleeIndex == 1); + __ mov(edi, Operand(esp, 1 * kPointerSize)); + __ AssertNotSmi(edi); + __ mov(FieldOperand(eax, JSSloppyArgumentsObject::kCalleeOffset), edi); + + // Use the length (smi tagged) and set that as an in-object property too. + __ AssertSmi(ecx); + __ mov(FieldOperand(eax, JSSloppyArgumentsObject::kLengthOffset), ecx); + + // Set up the elements pointer in the allocated arguments object. + // If we allocated a parameter map, edi will point there, otherwise to the + // backing store. + __ lea(edi, Operand(eax, JSSloppyArgumentsObject::kSize)); + __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); + + // eax = address of new object (tagged) + // ebx = mapped parameter count (tagged) + // ecx = argument count (tagged) + // edx = address of receiver argument + // edi = address of parameter map or backing store (tagged) + // esp[0] = mapped parameter count (tagged) + // esp[4] = function + // esp[8] = parameter count (tagged) + // Free two registers. + __ push(edx); + __ push(eax); + + // Initialize parameter map. If there are no mapped arguments, we're done. + Label skip_parameter_map; + __ test(ebx, ebx); + __ j(zero, &skip_parameter_map); + + __ mov(FieldOperand(edi, FixedArray::kMapOffset), + Immediate(isolate()->factory()->sloppy_arguments_elements_map())); + __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2)))); + __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); + __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); + __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); + __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); + + // Copy the parameter slots and the holes in the arguments. + // We need to fill in mapped_parameter_count slots. They index the context, + // where parameters are stored in reverse order, at + // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 + // The mapped parameter thus need to get indices + // MIN_CONTEXT_SLOTS+parameter_count-1 .. + // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count + // We loop from right to left. + Label parameters_loop, parameters_test; + __ push(ecx); + __ mov(eax, Operand(esp, 3 * kPointerSize)); + __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); + __ add(ebx, Operand(esp, 5 * kPointerSize)); + __ sub(ebx, eax); + __ mov(ecx, isolate()->factory()->the_hole_value()); + __ mov(edx, edi); + __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); + // eax = loop variable (tagged) + // ebx = mapping index (tagged) + // ecx = the hole value + // edx = address of parameter map (tagged) + // edi = address of backing store (tagged) + // esp[0] = argument count (tagged) + // esp[4] = address of new object (tagged) + // esp[8] = address of receiver argument + // esp[12] = mapped parameter count (tagged) + // esp[16] = function + // esp[20] = parameter count (tagged) + __ jmp(¶meters_test, Label::kNear); + + __ bind(¶meters_loop); + __ sub(eax, Immediate(Smi::FromInt(1))); + __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); + __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); + __ add(ebx, Immediate(Smi::FromInt(1))); + __ bind(¶meters_test); + __ test(eax, eax); + __ j(not_zero, ¶meters_loop, Label::kNear); + __ pop(ecx); + + __ bind(&skip_parameter_map); + + // ecx = argument count (tagged) + // edi = address of backing store (tagged) + // esp[0] = address of new object (tagged) + // esp[4] = address of receiver argument + // esp[8] = mapped parameter count (tagged) + // esp[12] = function + // esp[16] = parameter count (tagged) + // Copy arguments header and remaining slots (if there are any). + __ mov(FieldOperand(edi, FixedArray::kMapOffset), + Immediate(isolate()->factory()->fixed_array_map())); + __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); + + Label arguments_loop, arguments_test; + __ mov(ebx, Operand(esp, 2 * kPointerSize)); + __ mov(edx, Operand(esp, 1 * kPointerSize)); + __ sub(edx, ebx); // Is there a smarter way to do negative scaling? + __ sub(edx, ebx); + __ jmp(&arguments_test, Label::kNear); + + __ bind(&arguments_loop); + __ sub(edx, Immediate(kPointerSize)); + __ mov(eax, Operand(edx, 0)); + __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); + __ add(ebx, Immediate(Smi::FromInt(1))); + + __ bind(&arguments_test); + __ cmp(ebx, ecx); + __ j(less, &arguments_loop, Label::kNear); + + // Restore. + __ pop(eax); // Address of arguments object. + __ Drop(4); + + // Return. + __ ret(0); + + // Do the runtime call to allocate the arguments object. + __ bind(&runtime); + __ pop(eax); // Remove saved mapped parameter count. + __ pop(edi); // Pop saved function. + __ pop(eax); // Remove saved parameter count. + __ pop(eax); // Pop return address. + __ push(edi); // Push function. + __ push(edx); // Push parameters pointer. + __ push(ecx); // Push parameter count. + __ push(eax); // Push return address. + __ TailCallRuntime(Runtime::kNewSloppyArguments); +} + +void FastNewStrictArgumentsStub::Generate(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- edi : function + // -- esi : context + // -- ebp : frame pointer + // -- esp[0] : return address + // ----------------------------------- + __ AssertFunction(edi); + + // For Ignition we need to skip all possible handler/stub frames until + // we reach the JavaScript frame for the function (similar to what the + // runtime fallback implementation does). So make edx point to that + // JavaScript frame. + { + Label loop, loop_entry; + __ mov(edx, ebp); + __ jmp(&loop_entry, Label::kNear); + __ bind(&loop); + __ mov(edx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); + __ bind(&loop_entry); + __ cmp(edi, Operand(edx, StandardFrameConstants::kMarkerOffset)); + __ j(not_equal, &loop); + } + + // Check if we have an arguments adaptor frame below the function frame. + Label arguments_adaptor, arguments_done; + __ mov(ebx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); + __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset), + Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); + __ j(equal, &arguments_adaptor, Label::kNear); + { + __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); + __ mov(eax, + FieldOperand(eax, SharedFunctionInfo::kFormalParameterCountOffset)); + __ lea(ebx, + Operand(edx, eax, times_half_pointer_size, + StandardFrameConstants::kCallerSPOffset - 1 * kPointerSize)); + } + __ jmp(&arguments_done, Label::kNear); + __ bind(&arguments_adaptor); + { + __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); + __ lea(ebx, + Operand(ebx, eax, times_half_pointer_size, + StandardFrameConstants::kCallerSPOffset - 1 * kPointerSize)); + } + __ bind(&arguments_done); + + // ----------- S t a t e ------------- + // -- eax : number of arguments (tagged) + // -- ebx : pointer to the first argument + // -- esi : context + // -- esp[0] : return address + // ----------------------------------- + + // Allocate space for the strict arguments object plus the backing store. + Label allocate, done_allocate; + __ lea(ecx, + Operand(eax, times_half_pointer_size, + JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize)); + __ Allocate(ecx, edx, edi, no_reg, &allocate, TAG_OBJECT); + __ bind(&done_allocate); + + // Setup the elements array in edx. + __ mov(FieldOperand(edx, FixedArray::kMapOffset), + isolate()->factory()->fixed_array_map()); + __ mov(FieldOperand(edx, FixedArray::kLengthOffset), eax); + { + Label loop, done_loop; + __ Move(ecx, Smi::FromInt(0)); + __ bind(&loop); + __ cmp(ecx, eax); + __ j(equal, &done_loop, Label::kNear); + __ mov(edi, Operand(ebx, 0 * kPointerSize)); + __ mov(FieldOperand(edx, ecx, times_half_pointer_size, + FixedArray::kHeaderSize), + edi); + __ sub(ebx, Immediate(1 * kPointerSize)); + __ add(ecx, Immediate(Smi::FromInt(1))); + __ jmp(&loop); + __ bind(&done_loop); + } + + // Setup the rest parameter array in edi. + __ lea(edi, + Operand(edx, eax, times_half_pointer_size, FixedArray::kHeaderSize)); + __ LoadGlobalFunction(Context::STRICT_ARGUMENTS_MAP_INDEX, ecx); + __ mov(FieldOperand(edi, JSStrictArgumentsObject::kMapOffset), ecx); + __ mov(FieldOperand(edi, JSStrictArgumentsObject::kPropertiesOffset), + isolate()->factory()->empty_fixed_array()); + __ mov(FieldOperand(edi, JSStrictArgumentsObject::kElementsOffset), edx); + __ mov(FieldOperand(edi, JSStrictArgumentsObject::kLengthOffset), eax); + STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); + __ mov(eax, edi); + __ Ret(); + + // Fall back to %AllocateInNewSpace. + __ bind(&allocate); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ SmiTag(ecx); + __ Push(eax); + __ Push(ebx); + __ Push(ecx); + __ CallRuntime(Runtime::kAllocateInNewSpace); + __ mov(edx, eax); + __ Pop(ebx); + __ Pop(eax); + } + __ jmp(&done_allocate); +} void LoadGlobalViaContextStub::Generate(MacroAssembler* masm) { Register context_reg = esi; @@ -5150,11 +5372,10 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, __ jmp(&leave_exit_frame); } - static void CallApiFunctionStubHelper(MacroAssembler* masm, const ParameterCount& argc, bool return_first_arg, - bool call_data_undefined) { + bool call_data_undefined, bool is_lazy) { // ----------- S t a t e ------------- // -- edi : callee // -- ebx : call_data @@ -5228,8 +5449,10 @@ static void CallApiFunctionStubHelper(MacroAssembler* masm, // push return address __ push(return_address); - // load context from callee - __ mov(context, FieldOperand(callee, JSFunction::kContextOffset)); + if (!is_lazy) { + // load context from callee + __ mov(context, FieldOperand(callee, JSFunction::kContextOffset)); + } // API function gets reference to the v8::Arguments. If CPU profiler // is enabled wrapper function will be called and we need to pass @@ -5301,7 +5524,7 @@ static void CallApiFunctionStubHelper(MacroAssembler* masm, void CallApiFunctionStub::Generate(MacroAssembler* masm) { bool call_data_undefined = this->call_data_undefined(); CallApiFunctionStubHelper(masm, ParameterCount(eax), false, - call_data_undefined); + call_data_undefined, false); } @@ -5309,45 +5532,58 @@ void CallApiAccessorStub::Generate(MacroAssembler* masm) { bool is_store = this->is_store(); int argc = this->argc(); bool call_data_undefined = this->call_data_undefined(); + bool is_lazy = this->is_lazy(); CallApiFunctionStubHelper(masm, ParameterCount(argc), is_store, - call_data_undefined); + call_data_undefined, is_lazy); } void CallApiGetterStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8 - kArgsLength*4] : PropertyCallbackArguments object + // -- esp[0] : return address + // -- esp[4] : name + // -- esp[8 .. (8 + kArgsLength*4)] : v8::PropertyCallbackInfo::args_ // -- ... - // -- edx : api_function_address + // -- edx : api_function_address // ----------------------------------- DCHECK(edx.is(ApiGetterDescriptor::function_address())); - // array for v8::Arguments::values_, handler for name and pointer - // to the values (it considered as smi in GC). - const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2; - // Allocate space for opional callback address parameter in case - // CPU profiler is active. - const int kApiArgc = 2 + 1; + // v8::PropertyCallbackInfo::args_ array and name handle. + const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1; + + // Allocate v8::PropertyCallbackInfo object, arguments for callback and + // space for optional callback address parameter (in case CPU profiler is + // active) in non-GCed stack space. + const int kApiArgc = 3 + 1; Register api_function_address = edx; Register scratch = ebx; - // load address of name - __ lea(scratch, Operand(esp, 1 * kPointerSize)); + // Load address of v8::PropertyAccessorInfo::args_ array. + __ lea(scratch, Operand(esp, 2 * kPointerSize)); PrepareCallApiFunction(masm, kApiArgc); + // Create v8::PropertyCallbackInfo object on the stack and initialize + // it's args_ field. + Operand info_object = ApiParameterOperand(3); + __ mov(info_object, scratch); + + __ sub(scratch, Immediate(kPointerSize)); __ mov(ApiParameterOperand(0), scratch); // name. - __ add(scratch, Immediate(kPointerSize)); + __ lea(scratch, info_object); __ mov(ApiParameterOperand(1), scratch); // arguments pointer. + // Reserve space for optional callback address parameter. + Operand thunk_last_arg = ApiParameterOperand(2); ExternalReference thunk_ref = ExternalReference::invoke_accessor_getter_callback(isolate()); + // +3 is to skip prolog, return address and name handle. + Operand return_value_operand( + ebp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize); CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, - ApiParameterOperand(2), kStackSpace, nullptr, - Operand(ebp, 7 * kPointerSize), NULL); + thunk_last_arg, kStackUnwindSpace, nullptr, + return_value_operand, NULL); } |