summaryrefslogtreecommitdiff
path: root/deps/v8/src/ia32/code-stubs-ia32.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/ia32/code-stubs-ia32.cc')
-rw-r--r--deps/v8/src/ia32/code-stubs-ia32.cc1327
1 files changed, 788 insertions, 539 deletions
diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc
index 6e597e2814..2565c45d31 100644
--- a/deps/v8/src/ia32/code-stubs-ia32.cc
+++ b/deps/v8/src/ia32/code-stubs-ia32.cc
@@ -613,7 +613,6 @@ void MathPowStub::Generate(MacroAssembler* masm) {
__ Cvtsi2sd(double_exponent, exponent);
// Returning or bailing out.
- Counters* counters = isolate()->counters();
if (exponent_type() == ON_STACK) {
// The arguments are still on the stack.
__ bind(&call_runtime);
@@ -624,7 +623,6 @@ void MathPowStub::Generate(MacroAssembler* masm) {
__ bind(&done);
__ AllocateHeapNumber(eax, scratch, base, &call_runtime);
__ movsd(FieldOperand(eax, HeapNumber::kValueOffset), double_result);
- __ IncrementCounter(counters->math_pow(), 1);
__ ret(2 * kPointerSize);
} else {
__ bind(&call_runtime);
@@ -644,7 +642,6 @@ void MathPowStub::Generate(MacroAssembler* masm) {
__ add(esp, Immediate(kDoubleSize));
__ bind(&done);
- __ IncrementCounter(counters->math_pow(), 1);
__ ret(0);
}
}
@@ -730,456 +727,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(&parameters_test, Label::kNear);
-
- __ bind(&parameters_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(&parameters_test);
- __ test(eax, eax);
- __ j(not_zero, &parameters_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
@@ -1689,16 +1236,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,
@@ -1718,12 +1260,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);
@@ -1868,7 +1404,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.
@@ -1877,26 +1413,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);
@@ -1917,8 +1459,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);
@@ -2147,7 +1688,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);
@@ -2186,7 +1728,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);
@@ -2303,16 +1845,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)
@@ -2327,14 +1875,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;
@@ -3130,6 +2700,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, &not_name, Label::kNear);
+ __ Ret();
+ __ bind(&not_name);
+
+ Label not_heap_number;
+ __ CompareMap(eax, masm->isolate()->factory()->heap_number_map());
+ __ j(not_equal, &not_heap_number, Label::kNear);
+ __ bind(&is_number);
+ NumberToStringStub stub(isolate());
+ __ TailCallStub(&stub);
+ __ bind(&not_heap_number);
+
+ Label not_oddball;
+ __ CmpInstanceType(edi, ODDBALL_TYPE);
+ __ j(not_equal, &not_oddball, Label::kNear);
+ __ mov(eax, FieldOperand(eax, Oddball::kToStringOffset));
+ __ Ret();
+ __ bind(&not_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,
@@ -3333,21 +2939,17 @@ 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);
- __ push(eax);
- __ mov(eax, edx);
- __ pop(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);
+ __ push(eax);
+ __ mov(eax, edx);
+ __ pop(edx);
}
+ __ sub(eax, edx);
+ __ Ret();
__ bind(&miss);
GenerateMiss(masm);
@@ -3437,7 +3039,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);
@@ -3680,8 +3282,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);
@@ -3985,11 +3585,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.
@@ -5133,6 +4730,644 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
}
+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(&parameters_test, Label::kNear);
+
+ __ bind(&parameters_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(&parameters_test);
+ __ test(eax, eax);
+ __ j(not_zero, &parameters_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;
Register slot_reg = ebx;
@@ -5470,11 +5705,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
@@ -5548,8 +5782,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
@@ -5621,7 +5857,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);
}
@@ -5629,45 +5865,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);
}