diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2011-10-10 11:52:42 -0700 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2011-10-10 11:52:42 -0700 |
commit | 56e6952e639ba1557a5b22333788583e9e39fa29 (patch) | |
tree | 4937ad22037de82e7be0caf7d6bc2a4d4655db51 /deps/v8/src/mips/builtins-mips.cc | |
parent | 0fec21365612621cedaabeec6300d97e49c601c0 (diff) | |
download | node-56e6952e639ba1557a5b22333788583e9e39fa29.tar.gz |
Upgrade V8 to 3.6.6
Diffstat (limited to 'deps/v8/src/mips/builtins-mips.cc')
-rw-r--r-- | deps/v8/src/mips/builtins-mips.cc | 1151 |
1 files changed, 609 insertions, 542 deletions
diff --git a/deps/v8/src/mips/builtins-mips.cc b/deps/v8/src/mips/builtins-mips.cc index d77230448..f89dca926 100644 --- a/deps/v8/src/mips/builtins-mips.cc +++ b/deps/v8/src/mips/builtins-mips.cc @@ -587,10 +587,11 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { __ bind(&convert_argument); __ push(function); // Preserve the function. __ IncrementCounter(counters->string_ctor_conversions(), 1, a3, t0); - __ EnterInternalFrame(); - __ push(v0); - __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION); - __ LeaveInternalFrame(); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ push(v0); + __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION); + } __ pop(function); __ mov(argument, v0); __ Branch(&argument_is_string); @@ -606,10 +607,11 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { // create a string wrapper. __ bind(&gc_required); __ IncrementCounter(counters->string_ctor_gc_required(), 1, a3, t0); - __ EnterInternalFrame(); - __ push(argument); - __ CallRuntime(Runtime::kNewStringWrapper, 1); - __ LeaveInternalFrame(); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ push(argument); + __ CallRuntime(Runtime::kNewStringWrapper, 1); + } __ Ret(); } @@ -622,13 +624,13 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // -- sp[...]: constructor arguments // ----------------------------------- - Label non_function_call; + Label slow, non_function_call; // Check that the function is not a smi. __ And(t0, a1, Operand(kSmiTagMask)); __ Branch(&non_function_call, eq, t0, Operand(zero_reg)); // Check that the function is a JSFunction. __ GetObjectType(a1, a2, a2); - __ Branch(&non_function_call, ne, a2, Operand(JS_FUNCTION_TYPE)); + __ Branch(&slow, ne, a2, Operand(JS_FUNCTION_TYPE)); // Jump to the function-specific construct stub. __ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); @@ -638,13 +640,21 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // a0: number of arguments // a1: called object + // a2: object type + Label do_call; + __ bind(&slow); + __ Branch(&non_function_call, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE)); + __ GetBuiltinEntry(a3, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR); + __ jmp(&do_call); + __ bind(&non_function_call); + __ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); + __ bind(&do_call); // CALL_NON_FUNCTION expects the non-function constructor as receiver // (instead of the original receiver from the call site). The receiver is // stack element argc. // Set expected number of arguments to zero (not changing a0). __ mov(a2, zero_reg); - __ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); __ SetCallKind(t1, CALL_AS_METHOD); __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), RelocInfo::CODE_TARGET); @@ -667,331 +677,335 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // ----------------------------------- // Enter a construct frame. - __ EnterConstructFrame(); + { + FrameScope scope(masm, StackFrame::CONSTRUCT); - // Preserve the two incoming parameters on the stack. - __ sll(a0, a0, kSmiTagSize); // Tag arguments count. - __ MultiPushReversed(a0.bit() | a1.bit()); + // Preserve the two incoming parameters on the stack. + __ sll(a0, a0, kSmiTagSize); // Tag arguments count. + __ MultiPushReversed(a0.bit() | a1.bit()); - // Use t7 to hold undefined, which is used in several places below. - __ LoadRoot(t7, Heap::kUndefinedValueRootIndex); + // Use t7 to hold undefined, which is used in several places below. + __ LoadRoot(t7, Heap::kUndefinedValueRootIndex); - Label rt_call, allocated; - // Try to allocate the object without transitioning into C code. If any of the - // preconditions is not met, the code bails out to the runtime call. - if (FLAG_inline_new) { - Label undo_allocation; + Label rt_call, allocated; + // Try to allocate the object without transitioning into C code. If any of + // the preconditions is not met, the code bails out to the runtime call. + if (FLAG_inline_new) { + Label undo_allocation; #ifdef ENABLE_DEBUGGER_SUPPORT - ExternalReference debug_step_in_fp = - ExternalReference::debug_step_in_fp_address(isolate); - __ li(a2, Operand(debug_step_in_fp)); - __ lw(a2, MemOperand(a2)); - __ Branch(&rt_call, ne, a2, Operand(zero_reg)); + ExternalReference debug_step_in_fp = + ExternalReference::debug_step_in_fp_address(isolate); + __ li(a2, Operand(debug_step_in_fp)); + __ lw(a2, MemOperand(a2)); + __ Branch(&rt_call, ne, a2, Operand(zero_reg)); #endif - // Load the initial map and verify that it is in fact a map. - // a1: constructor function - __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); - __ And(t0, a2, Operand(kSmiTagMask)); - __ Branch(&rt_call, eq, t0, Operand(zero_reg)); - __ GetObjectType(a2, a3, t4); - __ Branch(&rt_call, ne, t4, Operand(MAP_TYPE)); + // Load the initial map and verify that it is in fact a map. + // a1: constructor function + __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); + __ And(t0, a2, Operand(kSmiTagMask)); + __ Branch(&rt_call, eq, t0, Operand(zero_reg)); + __ GetObjectType(a2, a3, t4); + __ Branch(&rt_call, ne, t4, Operand(MAP_TYPE)); + + // Check that the constructor is not constructing a JSFunction (see + // comments in Runtime_NewObject in runtime.cc). In which case the + // initial map's instance type would be JS_FUNCTION_TYPE. + // a1: constructor function + // a2: initial map + __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset)); + __ Branch(&rt_call, eq, a3, Operand(JS_FUNCTION_TYPE)); - // Check that the constructor is not constructing a JSFunction (see comments - // in Runtime_NewObject in runtime.cc). In which case the initial map's - // instance type would be JS_FUNCTION_TYPE. - // a1: constructor function - // a2: initial map - __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset)); - __ Branch(&rt_call, eq, a3, Operand(JS_FUNCTION_TYPE)); - - if (count_constructions) { - Label allocate; - // Decrease generous allocation count. - __ lw(a3, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); - MemOperand constructor_count = - FieldMemOperand(a3, SharedFunctionInfo::kConstructionCountOffset); - __ lbu(t0, constructor_count); - __ Subu(t0, t0, Operand(1)); - __ sb(t0, constructor_count); - __ Branch(&allocate, ne, t0, Operand(zero_reg)); - - __ Push(a1, a2); - - __ push(a1); // Constructor. - // The call will replace the stub, so the countdown is only done once. - __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); - - __ pop(a2); - __ pop(a1); - - __ bind(&allocate); - } - - // Now allocate the JSObject on the heap. - // a1: constructor function - // a2: initial map - __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset)); - __ AllocateInNewSpace(a3, t4, t5, t6, &rt_call, SIZE_IN_WORDS); - - // Allocated the JSObject, now initialize the fields. Map is set to initial - // map and properties and elements are set to empty fixed array. - // a1: constructor function - // a2: initial map - // a3: object size - // t4: JSObject (not tagged) - __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex); - __ mov(t5, t4); - __ sw(a2, MemOperand(t5, JSObject::kMapOffset)); - __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset)); - __ sw(t6, MemOperand(t5, JSObject::kElementsOffset)); - __ Addu(t5, t5, Operand(3*kPointerSize)); - ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); - ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset); - ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset); - - // Fill all the in-object properties with appropriate filler. - // a1: constructor function - // a2: initial map - // a3: object size (in words) - // t4: JSObject (not tagged) - // t5: First in-object property of JSObject (not tagged) - __ sll(t0, a3, kPointerSizeLog2); - __ addu(t6, t4, t0); // End of object. - ASSERT_EQ(3 * kPointerSize, JSObject::kHeaderSize); - { Label loop, entry; if (count_constructions) { - // To allow for truncation. - __ LoadRoot(t7, Heap::kOnePointerFillerMapRootIndex); - } else { - __ LoadRoot(t7, Heap::kUndefinedValueRootIndex); + Label allocate; + // Decrease generous allocation count. + __ lw(a3, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); + MemOperand constructor_count = + FieldMemOperand(a3, SharedFunctionInfo::kConstructionCountOffset); + __ lbu(t0, constructor_count); + __ Subu(t0, t0, Operand(1)); + __ sb(t0, constructor_count); + __ Branch(&allocate, ne, t0, Operand(zero_reg)); + + __ Push(a1, a2); + + __ push(a1); // Constructor. + // The call will replace the stub, so the countdown is only done once. + __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); + + __ pop(a2); + __ pop(a1); + + __ bind(&allocate); } - __ jmp(&entry); - __ bind(&loop); - __ sw(t7, MemOperand(t5, 0)); - __ addiu(t5, t5, kPointerSize); - __ bind(&entry); - __ Branch(&loop, Uless, t5, Operand(t6)); - } - // Add the object tag to make the JSObject real, so that we can continue and - // jump into the continuation code at any time from now on. Any failures - // need to undo the allocation, so that the heap is in a consistent state - // and verifiable. - __ Addu(t4, t4, Operand(kHeapObjectTag)); + // Now allocate the JSObject on the heap. + // a1: constructor function + // a2: initial map + __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset)); + __ AllocateInNewSpace(a3, t4, t5, t6, &rt_call, SIZE_IN_WORDS); + + // Allocated the JSObject, now initialize the fields. Map is set to + // initial map and properties and elements are set to empty fixed array. + // a1: constructor function + // a2: initial map + // a3: object size + // t4: JSObject (not tagged) + __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex); + __ mov(t5, t4); + __ sw(a2, MemOperand(t5, JSObject::kMapOffset)); + __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset)); + __ sw(t6, MemOperand(t5, JSObject::kElementsOffset)); + __ Addu(t5, t5, Operand(3*kPointerSize)); + ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); + ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset); + ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset); + + // Fill all the in-object properties with appropriate filler. + // a1: constructor function + // a2: initial map + // a3: object size (in words) + // t4: JSObject (not tagged) + // t5: First in-object property of JSObject (not tagged) + __ sll(t0, a3, kPointerSizeLog2); + __ addu(t6, t4, t0); // End of object. + ASSERT_EQ(3 * kPointerSize, JSObject::kHeaderSize); + { Label loop, entry; + if (count_constructions) { + // To allow for truncation. + __ LoadRoot(t7, Heap::kOnePointerFillerMapRootIndex); + } else { + __ LoadRoot(t7, Heap::kUndefinedValueRootIndex); + } + __ jmp(&entry); + __ bind(&loop); + __ sw(t7, MemOperand(t5, 0)); + __ addiu(t5, t5, kPointerSize); + __ bind(&entry); + __ Branch(&loop, Uless, t5, Operand(t6)); + } - // Check if a non-empty properties array is needed. Continue with allocated - // object if not fall through to runtime call if it is. - // a1: constructor function - // t4: JSObject - // t5: start of next object (not tagged) - __ lbu(a3, FieldMemOperand(a2, Map::kUnusedPropertyFieldsOffset)); - // The field instance sizes contains both pre-allocated property fields and - // in-object properties. - __ lw(a0, FieldMemOperand(a2, Map::kInstanceSizesOffset)); - __ And(t6, - a0, - Operand(0x000000FF << Map::kPreAllocatedPropertyFieldsByte * 8)); - __ srl(t0, t6, Map::kPreAllocatedPropertyFieldsByte * 8); - __ Addu(a3, a3, Operand(t0)); - __ And(t6, a0, Operand(0x000000FF << Map::kInObjectPropertiesByte * 8)); - __ srl(t0, t6, Map::kInObjectPropertiesByte * 8); - __ subu(a3, a3, t0); - - // Done if no extra properties are to be allocated. - __ Branch(&allocated, eq, a3, Operand(zero_reg)); - __ Assert(greater_equal, "Property allocation count failed.", - a3, Operand(zero_reg)); - - // Scale the number of elements by pointer size and add the header for - // FixedArrays to the start of the next object calculation from above. - // a1: constructor - // a3: number of elements in properties array - // t4: JSObject - // t5: start of next object - __ Addu(a0, a3, Operand(FixedArray::kHeaderSize / kPointerSize)); - __ AllocateInNewSpace( - a0, - t5, - t6, - a2, - &undo_allocation, - static_cast<AllocationFlags>(RESULT_CONTAINS_TOP | SIZE_IN_WORDS)); - - // Initialize the FixedArray. - // a1: constructor - // a3: number of elements in properties array (un-tagged) - // t4: JSObject - // t5: start of next object - __ LoadRoot(t6, Heap::kFixedArrayMapRootIndex); - __ mov(a2, t5); - __ sw(t6, MemOperand(a2, JSObject::kMapOffset)); - __ sll(a0, a3, kSmiTagSize); - __ sw(a0, MemOperand(a2, FixedArray::kLengthOffset)); - __ Addu(a2, a2, Operand(2 * kPointerSize)); - - ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); - ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); - - // Initialize the fields to undefined. - // a1: constructor - // a2: First element of FixedArray (not tagged) - // a3: number of elements in properties array - // t4: JSObject - // t5: FixedArray (not tagged) - __ sll(t3, a3, kPointerSizeLog2); - __ addu(t6, a2, t3); // End of object. - ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize); - { Label loop, entry; - if (count_constructions) { - __ LoadRoot(t7, Heap::kUndefinedValueRootIndex); - } else if (FLAG_debug_code) { - __ LoadRoot(t8, Heap::kUndefinedValueRootIndex); - __ Assert(eq, "Undefined value not loaded.", t7, Operand(t8)); + // Add the object tag to make the JSObject real, so that we can continue + // and jump into the continuation code at any time from now on. Any + // failures need to undo the allocation, so that the heap is in a + // consistent state and verifiable. + __ Addu(t4, t4, Operand(kHeapObjectTag)); + + // Check if a non-empty properties array is needed. Continue with + // allocated object if not fall through to runtime call if it is. + // a1: constructor function + // t4: JSObject + // t5: start of next object (not tagged) + __ lbu(a3, FieldMemOperand(a2, Map::kUnusedPropertyFieldsOffset)); + // The field instance sizes contains both pre-allocated property fields + // and in-object properties. + __ lw(a0, FieldMemOperand(a2, Map::kInstanceSizesOffset)); + __ And(t6, + a0, + Operand(0x000000FF << Map::kPreAllocatedPropertyFieldsByte * 8)); + __ srl(t0, t6, Map::kPreAllocatedPropertyFieldsByte * 8); + __ Addu(a3, a3, Operand(t0)); + __ And(t6, a0, Operand(0x000000FF << Map::kInObjectPropertiesByte * 8)); + __ srl(t0, t6, Map::kInObjectPropertiesByte * 8); + __ subu(a3, a3, t0); + + // Done if no extra properties are to be allocated. + __ Branch(&allocated, eq, a3, Operand(zero_reg)); + __ Assert(greater_equal, "Property allocation count failed.", + a3, Operand(zero_reg)); + + // Scale the number of elements by pointer size and add the header for + // FixedArrays to the start of the next object calculation from above. + // a1: constructor + // a3: number of elements in properties array + // t4: JSObject + // t5: start of next object + __ Addu(a0, a3, Operand(FixedArray::kHeaderSize / kPointerSize)); + __ AllocateInNewSpace( + a0, + t5, + t6, + a2, + &undo_allocation, + static_cast<AllocationFlags>(RESULT_CONTAINS_TOP | SIZE_IN_WORDS)); + + // Initialize the FixedArray. + // a1: constructor + // a3: number of elements in properties array (un-tagged) + // t4: JSObject + // t5: start of next object + __ LoadRoot(t6, Heap::kFixedArrayMapRootIndex); + __ mov(a2, t5); + __ sw(t6, MemOperand(a2, JSObject::kMapOffset)); + __ sll(a0, a3, kSmiTagSize); + __ sw(a0, MemOperand(a2, FixedArray::kLengthOffset)); + __ Addu(a2, a2, Operand(2 * kPointerSize)); + + ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); + ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); + + // Initialize the fields to undefined. + // a1: constructor + // a2: First element of FixedArray (not tagged) + // a3: number of elements in properties array + // t4: JSObject + // t5: FixedArray (not tagged) + __ sll(t3, a3, kPointerSizeLog2); + __ addu(t6, a2, t3); // End of object. + ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize); + { Label loop, entry; + if (count_constructions) { + __ LoadRoot(t7, Heap::kUndefinedValueRootIndex); + } else if (FLAG_debug_code) { + __ LoadRoot(t8, Heap::kUndefinedValueRootIndex); + __ Assert(eq, "Undefined value not loaded.", t7, Operand(t8)); + } + __ jmp(&entry); + __ bind(&loop); + __ sw(t7, MemOperand(a2)); + __ addiu(a2, a2, kPointerSize); + __ bind(&entry); + __ Branch(&loop, less, a2, Operand(t6)); } - __ jmp(&entry); - __ bind(&loop); - __ sw(t7, MemOperand(a2)); - __ addiu(a2, a2, kPointerSize); - __ bind(&entry); - __ Branch(&loop, less, a2, Operand(t6)); + + // Store the initialized FixedArray into the properties field of + // the JSObject. + // a1: constructor function + // t4: JSObject + // t5: FixedArray (not tagged) + __ Addu(t5, t5, Operand(kHeapObjectTag)); // Add the heap tag. + __ sw(t5, FieldMemOperand(t4, JSObject::kPropertiesOffset)); + + // Continue with JSObject being successfully allocated. + // a1: constructor function + // a4: JSObject + __ jmp(&allocated); + + // Undo the setting of the new top so that the heap is verifiable. For + // example, the map's unused properties potentially do not match the + // allocated objects unused properties. + // t4: JSObject (previous new top) + __ bind(&undo_allocation); + __ UndoAllocationInNewSpace(t4, t5); } - // Store the initialized FixedArray into the properties field of - // the JSObject. + __ bind(&rt_call); + // Allocate the new receiver object using the runtime call. // a1: constructor function - // t4: JSObject - // t5: FixedArray (not tagged) - __ Addu(t5, t5, Operand(kHeapObjectTag)); // Add the heap tag. - __ sw(t5, FieldMemOperand(t4, JSObject::kPropertiesOffset)); + __ push(a1); // Argument for Runtime_NewObject. + __ CallRuntime(Runtime::kNewObject, 1); + __ mov(t4, v0); - // Continue with JSObject being successfully allocated. - // a1: constructor function - // a4: JSObject - __ jmp(&allocated); - - // Undo the setting of the new top so that the heap is verifiable. For - // example, the map's unused properties potentially do not match the - // allocated objects unused properties. - // t4: JSObject (previous new top) - __ bind(&undo_allocation); - __ UndoAllocationInNewSpace(t4, t5); - } + // Receiver for constructor call allocated. + // t4: JSObject + __ bind(&allocated); + __ push(t4); - __ bind(&rt_call); - // Allocate the new receiver object using the runtime call. - // a1: constructor function - __ push(a1); // Argument for Runtime_NewObject. - __ CallRuntime(Runtime::kNewObject, 1); - __ mov(t4, v0); + // Push the function and the allocated receiver from the stack. + // sp[0]: receiver (newly allocated object) + // sp[1]: constructor function + // sp[2]: number of arguments (smi-tagged) + __ lw(a1, MemOperand(sp, kPointerSize)); + __ MultiPushReversed(a1.bit() | t4.bit()); - // Receiver for constructor call allocated. - // t4: JSObject - __ bind(&allocated); - __ push(t4); + // Reload the number of arguments from the stack. + // a1: constructor function + // sp[0]: receiver + // sp[1]: constructor function + // sp[2]: receiver + // sp[3]: constructor function + // sp[4]: number of arguments (smi-tagged) + __ lw(a3, MemOperand(sp, 4 * kPointerSize)); - // Push the function and the allocated receiver from the stack. - // sp[0]: receiver (newly allocated object) - // sp[1]: constructor function - // sp[2]: number of arguments (smi-tagged) - __ lw(a1, MemOperand(sp, kPointerSize)); - __ MultiPushReversed(a1.bit() | t4.bit()); + // Setup pointer to last argument. + __ Addu(a2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); - // Reload the number of arguments from the stack. - // a1: constructor function - // sp[0]: receiver - // sp[1]: constructor function - // sp[2]: receiver - // sp[3]: constructor function - // sp[4]: number of arguments (smi-tagged) - __ lw(a3, MemOperand(sp, 4 * kPointerSize)); + // Setup number of arguments for function call below. + __ srl(a0, a3, kSmiTagSize); - // Setup pointer to last argument. - __ Addu(a2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); + // Copy arguments and receiver to the expression stack. + // a0: number of arguments + // a1: constructor function + // a2: address of last argument (caller sp) + // a3: number of arguments (smi-tagged) + // sp[0]: receiver + // sp[1]: constructor function + // sp[2]: receiver + // sp[3]: constructor function + // sp[4]: number of arguments (smi-tagged) + Label loop, entry; + __ jmp(&entry); + __ bind(&loop); + __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize); + __ Addu(t0, a2, Operand(t0)); + __ lw(t1, MemOperand(t0)); + __ push(t1); + __ bind(&entry); + __ Addu(a3, a3, Operand(-2)); + __ Branch(&loop, greater_equal, a3, Operand(zero_reg)); - // Setup number of arguments for function call below. - __ srl(a0, a3, kSmiTagSize); + // Call the function. + // a0: number of arguments + // a1: constructor function + if (is_api_function) { + __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); + Handle<Code> code = + masm->isolate()->builtins()->HandleApiCallConstruct(); + ParameterCount expected(0); + __ InvokeCode(code, expected, expected, + RelocInfo::CODE_TARGET, CALL_FUNCTION, CALL_AS_METHOD); + } else { + ParameterCount actual(a0); + __ InvokeFunction(a1, actual, CALL_FUNCTION, + NullCallWrapper(), CALL_AS_METHOD); + } - // Copy arguments and receiver to the expression stack. - // a0: number of arguments - // a1: constructor function - // a2: address of last argument (caller sp) - // a3: number of arguments (smi-tagged) - // sp[0]: receiver - // sp[1]: constructor function - // sp[2]: receiver - // sp[3]: constructor function - // sp[4]: number of arguments (smi-tagged) - Label loop, entry; - __ jmp(&entry); - __ bind(&loop); - __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize); - __ Addu(t0, a2, Operand(t0)); - __ lw(t1, MemOperand(t0)); - __ push(t1); - __ bind(&entry); - __ Addu(a3, a3, Operand(-2)); - __ Branch(&loop, greater_equal, a3, Operand(zero_reg)); + // Pop the function from the stack. + // v0: result + // sp[0]: constructor function + // sp[2]: receiver + // sp[3]: constructor function + // sp[4]: number of arguments (smi-tagged) + __ Pop(); - // Call the function. - // a0: number of arguments - // a1: constructor function - if (is_api_function) { - __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); - Handle<Code> code = - masm->isolate()->builtins()->HandleApiCallConstruct(); - ParameterCount expected(0); - __ InvokeCode(code, expected, expected, - RelocInfo::CODE_TARGET, CALL_FUNCTION, CALL_AS_METHOD); - } else { - ParameterCount actual(a0); - __ InvokeFunction(a1, actual, CALL_FUNCTION, - NullCallWrapper(), CALL_AS_METHOD); + // Restore context from the frame. + __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + + // If the result is an object (in the ECMA sense), we should get rid + // of the receiver and use the result; see ECMA-262 section 13.2.2-7 + // on page 74. + Label use_receiver, exit; + + // If the result is a smi, it is *not* an object in the ECMA sense. + // v0: result + // sp[0]: receiver (newly allocated object) + // sp[1]: constructor function + // sp[2]: number of arguments (smi-tagged) + __ And(t0, v0, Operand(kSmiTagMask)); + __ Branch(&use_receiver, eq, t0, Operand(zero_reg)); + + // If the type of the result (stored in its map) is less than + // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. + __ GetObjectType(v0, a3, a3); + __ Branch(&exit, greater_equal, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); + + // Throw away the result of the constructor invocation and use the + // on-stack receiver as the result. + __ bind(&use_receiver); + __ lw(v0, MemOperand(sp)); + + // Remove receiver from the stack, remove caller arguments, and + // return. + __ bind(&exit); + // v0: result + // sp[0]: receiver (newly allocated object) + // sp[1]: constructor function + // sp[2]: number of arguments (smi-tagged) + __ lw(a1, MemOperand(sp, 2 * kPointerSize)); + + // Leave construct frame. } - // Pop the function from the stack. - // v0: result - // sp[0]: constructor function - // sp[2]: receiver - // sp[3]: constructor function - // sp[4]: number of arguments (smi-tagged) - __ Pop(); - - // Restore context from the frame. - __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - - // If the result is an object (in the ECMA sense), we should get rid - // of the receiver and use the result; see ECMA-262 section 13.2.2-7 - // on page 74. - Label use_receiver, exit; - - // If the result is a smi, it is *not* an object in the ECMA sense. - // v0: result - // sp[0]: receiver (newly allocated object) - // sp[1]: constructor function - // sp[2]: number of arguments (smi-tagged) - __ And(t0, v0, Operand(kSmiTagMask)); - __ Branch(&use_receiver, eq, t0, Operand(zero_reg)); - - // If the type of the result (stored in its map) is less than - // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. - __ GetObjectType(v0, a3, a3); - __ Branch(&exit, greater_equal, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); - - // Throw away the result of the constructor invocation and use the - // on-stack receiver as the result. - __ bind(&use_receiver); - __ lw(v0, MemOperand(sp)); - - // Remove receiver from the stack, remove caller arguments, and - // return. - __ bind(&exit); - // v0: result - // sp[0]: receiver (newly allocated object) - // sp[1]: constructor function - // sp[2]: number of arguments (smi-tagged) - __ lw(a1, MemOperand(sp, 2 * kPointerSize)); - __ LeaveConstructFrame(); __ sll(t0, a1, kPointerSizeLog2 - 1); __ Addu(sp, sp, t0); __ Addu(sp, sp, kPointerSize); @@ -1031,58 +1045,60 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, __ mov(cp, zero_reg); // Enter an internal frame. - __ EnterInternalFrame(); + { + FrameScope scope(masm, StackFrame::INTERNAL); - // Set up the context from the function argument. - __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); + // Set up the context from the function argument. + __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); - // Set up the roots register. - ExternalReference roots_address = - ExternalReference::roots_address(masm->isolate()); - __ li(s6, Operand(roots_address)); + // Set up the roots register. + ExternalReference roots_address = + ExternalReference::roots_address(masm->isolate()); + __ li(s6, Operand(roots_address)); - // Push the function and the receiver onto the stack. - __ Push(a1, a2); + // Push the function and the receiver onto the stack. + __ Push(a1, a2); - // Copy arguments to the stack in a loop. - // a3: argc - // s0: argv, ie points to first arg - Label loop, entry; - __ sll(t0, a3, kPointerSizeLog2); - __ addu(t2, s0, t0); - __ b(&entry); - __ nop(); // Branch delay slot nop. - // t2 points past last arg. - __ bind(&loop); - __ lw(t0, MemOperand(s0)); // Read next parameter. - __ addiu(s0, s0, kPointerSize); - __ lw(t0, MemOperand(t0)); // Dereference handle. - __ push(t0); // Push parameter. - __ bind(&entry); - __ Branch(&loop, ne, s0, Operand(t2)); - - // Initialize all JavaScript callee-saved registers, since they will be seen - // by the garbage collector as part of handlers. - __ LoadRoot(t0, Heap::kUndefinedValueRootIndex); - __ mov(s1, t0); - __ mov(s2, t0); - __ mov(s3, t0); - __ mov(s4, t0); - __ mov(s5, t0); - // s6 holds the root address. Do not clobber. - // s7 is cp. Do not init. - - // Invoke the code and pass argc as a0. - __ mov(a0, a3); - if (is_construct) { - __ Call(masm->isolate()->builtins()->JSConstructCall()); - } else { - ParameterCount actual(a0); - __ InvokeFunction(a1, actual, CALL_FUNCTION, - NullCallWrapper(), CALL_AS_METHOD); - } + // Copy arguments to the stack in a loop. + // a3: argc + // s0: argv, ie points to first arg + Label loop, entry; + __ sll(t0, a3, kPointerSizeLog2); + __ addu(t2, s0, t0); + __ b(&entry); + __ nop(); // Branch delay slot nop. + // t2 points past last arg. + __ bind(&loop); + __ lw(t0, MemOperand(s0)); // Read next parameter. + __ addiu(s0, s0, kPointerSize); + __ lw(t0, MemOperand(t0)); // Dereference handle. + __ push(t0); // Push parameter. + __ bind(&entry); + __ Branch(&loop, ne, s0, Operand(t2)); - __ LeaveInternalFrame(); + // Initialize all JavaScript callee-saved registers, since they will be seen + // by the garbage collector as part of handlers. + __ LoadRoot(t0, Heap::kUndefinedValueRootIndex); + __ mov(s1, t0); + __ mov(s2, t0); + __ mov(s3, t0); + __ mov(s4, t0); + __ mov(s5, t0); + // s6 holds the root address. Do not clobber. + // s7 is cp. Do not init. + + // Invoke the code and pass argc as a0. + __ mov(a0, a3); + if (is_construct) { + __ Call(masm->isolate()->builtins()->JSConstructCall()); + } else { + ParameterCount actual(a0); + __ InvokeFunction(a1, actual, CALL_FUNCTION, + NullCallWrapper(), CALL_AS_METHOD); + } + + // Leave internal frame. + } __ Jump(ra); } @@ -1100,27 +1116,28 @@ void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { void Builtins::Generate_LazyCompile(MacroAssembler* masm) { // Enter an internal frame. - __ EnterInternalFrame(); + { + FrameScope scope(masm, StackFrame::INTERNAL); - // Preserve the function. - __ push(a1); - // Push call kind information. - __ push(t1); + // Preserve the function. + __ push(a1); + // Push call kind information. + __ push(t1); - // Push the function on the stack as the argument to the runtime function. - __ push(a1); - // Call the runtime function. - __ CallRuntime(Runtime::kLazyCompile, 1); - // Calculate the entry point. - __ addiu(t9, v0, Code::kHeaderSize - kHeapObjectTag); + // Push the function on the stack as the argument to the runtime function. + __ push(a1); + // Call the runtime function. + __ CallRuntime(Runtime::kLazyCompile, 1); + // Calculate the entry point. + __ addiu(t9, v0, Code::kHeaderSize - kHeapObjectTag); - // Restore call kind information. - __ pop(t1); - // Restore saved function. - __ pop(a1); + // Restore call kind information. + __ pop(t1); + // Restore saved function. + __ pop(a1); - // Tear down temporary frame. - __ LeaveInternalFrame(); + // Tear down temporary frame. + } // Do a tail-call of the compiled function. __ Jump(t9); @@ -1129,26 +1146,27 @@ void Builtins::Generate_LazyCompile(MacroAssembler* masm) { void Builtins::Generate_LazyRecompile(MacroAssembler* masm) { // Enter an internal frame. - __ EnterInternalFrame(); + { + FrameScope scope(masm, StackFrame::INTERNAL); - // Preserve the function. - __ push(a1); - // Push call kind information. - __ push(t1); + // Preserve the function. + __ push(a1); + // Push call kind information. + __ push(t1); - // Push the function on the stack as the argument to the runtime function. - __ push(a1); - __ CallRuntime(Runtime::kLazyRecompile, 1); - // Calculate the entry point. - __ Addu(t9, v0, Operand(Code::kHeaderSize - kHeapObjectTag)); + // Push the function on the stack as the argument to the runtime function. + __ push(a1); + __ CallRuntime(Runtime::kLazyRecompile, 1); + // Calculate the entry point. + __ Addu(t9, v0, Operand(Code::kHeaderSize - kHeapObjectTag)); - // Restore call kind information. - __ pop(t1); - // Restore saved function. - __ pop(a1); + // Restore call kind information. + __ pop(t1); + // Restore saved function. + __ pop(a1); - // Tear down temporary frame. - __ LeaveInternalFrame(); + // Tear down temporary frame. + } // Do a tail-call of the compiled function. __ Jump(t9); @@ -1190,19 +1208,20 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { // 2. Get the function to call (passed as receiver) from the stack, check // if it is a function. // a0: actual number of arguments - Label non_function; + Label slow, non_function; __ sll(at, a0, kPointerSizeLog2); __ addu(at, sp, at); __ lw(a1, MemOperand(at)); __ And(at, a1, Operand(kSmiTagMask)); __ Branch(&non_function, eq, at, Operand(zero_reg)); __ GetObjectType(a1, a2, a2); - __ Branch(&non_function, ne, a2, Operand(JS_FUNCTION_TYPE)); + __ Branch(&slow, ne, a2, Operand(JS_FUNCTION_TYPE)); // 3a. Patch the first argument if necessary when calling a function. // a0: actual number of arguments // a1: function Label shift_arguments; + __ li(t0, Operand(0, RelocInfo::NONE)); // Indicate regular JS_FUNCTION. { Label convert_to_object, use_global_receiver, patch_receiver; // Change context eagerly in case we need the global receiver. __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); @@ -1210,13 +1229,13 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { // Do not transform the receiver for strict mode functions. __ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); __ lw(a3, FieldMemOperand(a2, SharedFunctionInfo::kCompilerHintsOffset)); - __ And(t0, a3, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + + __ And(t3, a3, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize))); - __ Branch(&shift_arguments, ne, t0, Operand(zero_reg)); + __ Branch(&shift_arguments, ne, t3, Operand(zero_reg)); // Do not transform the receiver for native (Compilerhints already in a3). - __ And(t0, a3, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); - __ Branch(&shift_arguments, ne, t0, Operand(zero_reg)); + __ And(t3, a3, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); + __ Branch(&shift_arguments, ne, t3, Operand(zero_reg)); // Compute the receiver in non-strict mode. // Load first argument in a2. a2 = -kPointerSize(sp + n_args << 2). @@ -1238,21 +1257,25 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ Branch(&shift_arguments, ge, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); __ bind(&convert_to_object); - __ EnterInternalFrame(); // In order to preserve argument count. - __ sll(a0, a0, kSmiTagSize); // Smi tagged. - __ push(a0); - - __ push(a2); - __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); - __ mov(a2, v0); - - __ pop(a0); - __ sra(a0, a0, kSmiTagSize); // Un-tag. - __ LeaveInternalFrame(); - // Restore the function to a1. + // Enter an internal frame in order to preserve argument count. + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ sll(a0, a0, kSmiTagSize); // Smi tagged. + __ push(a0); + + __ push(a2); + __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); + __ mov(a2, v0); + + __ pop(a0); + __ sra(a0, a0, kSmiTagSize); // Un-tag. + // Leave internal frame. + } + // Restore the function to a1, and the flag to t0. __ sll(at, a0, kPointerSizeLog2); __ addu(at, sp, at); __ lw(a1, MemOperand(at)); + __ li(t0, Operand(0, RelocInfo::NONE)); __ Branch(&patch_receiver); // Use the global receiver object from the called function as the @@ -1273,25 +1296,31 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ Branch(&shift_arguments); } - // 3b. Patch the first argument when calling a non-function. The + // 3b. Check for function proxy. + __ bind(&slow); + __ li(t0, Operand(1, RelocInfo::NONE)); // Indicate function proxy. + __ Branch(&shift_arguments, eq, a2, Operand(JS_FUNCTION_PROXY_TYPE)); + + __ bind(&non_function); + __ li(t0, Operand(2, RelocInfo::NONE)); // Indicate non-function. + + // 3c. Patch the first argument when calling a non-function. The // CALL_NON_FUNCTION builtin expects the non-function callee as // receiver, so overwrite the first argument which will ultimately // become the receiver. // a0: actual number of arguments // a1: function - __ bind(&non_function); - // Restore the function in case it has been modified. + // t0: call type (0: JS function, 1: function proxy, 2: non-function) __ sll(at, a0, kPointerSizeLog2); __ addu(a2, sp, at); __ sw(a1, MemOperand(a2, -kPointerSize)); - // Clear a1 to indicate a non-function being called. - __ mov(a1, zero_reg); // 4. Shift arguments and return address one slot down on the stack // (overwriting the original receiver). Adjust argument count to make // the original first argument the new receiver. // a0: actual number of arguments // a1: function + // t0: call type (0: JS function, 1: function proxy, 2: non-function) __ bind(&shift_arguments); { Label loop; // Calculate the copy start address (destination). Copy end address is sp. @@ -1309,14 +1338,26 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ Pop(); } - // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin. + // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin, + // or a function proxy via CALL_FUNCTION_PROXY. // a0: actual number of arguments // a1: function - { Label function; - __ Branch(&function, ne, a1, Operand(zero_reg)); - __ mov(a2, zero_reg); // expected arguments is 0 for CALL_NON_FUNCTION - __ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION); + // t0: call type (0: JS function, 1: function proxy, 2: non-function) + { Label function, non_proxy; + __ Branch(&function, eq, t0, Operand(zero_reg)); + // Expected number of arguments is 0 for CALL_NON_FUNCTION. + __ mov(a2, zero_reg); __ SetCallKind(t1, CALL_AS_METHOD); + __ Branch(&non_proxy, ne, t0, Operand(1)); + + __ push(a1); // Re-add proxy object as additional argument. + __ Addu(a0, a0, Operand(1)); + __ GetBuiltinEntry(a3, Builtins::CALL_FUNCTION_PROXY); + __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), + RelocInfo::CODE_TARGET); + + __ bind(&non_proxy); + __ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION); __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), RelocInfo::CODE_TARGET); __ bind(&function); @@ -1350,134 +1391,160 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { const int kRecvOffset = 3 * kPointerSize; const int kFunctionOffset = 4 * kPointerSize; - __ EnterInternalFrame(); - - __ lw(a0, MemOperand(fp, kFunctionOffset)); // Get the function. - __ push(a0); - __ lw(a0, MemOperand(fp, kArgsOffset)); // Get the args array. - __ push(a0); - // Returns (in v0) number of arguments to copy to stack as Smi. - __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); - - // Check the stack for overflow. We are not trying need to catch - // interruptions (e.g. debug break and preemption) here, so the "real stack - // limit" is checked. - Label okay; - __ LoadRoot(a2, Heap::kRealStackLimitRootIndex); - // Make a2 the space we have left. The stack might already be overflowed - // here which will cause a2 to become negative. - __ subu(a2, sp, a2); - // Check if the arguments will overflow the stack. - __ sll(t0, v0, kPointerSizeLog2 - kSmiTagSize); - __ Branch(&okay, gt, a2, Operand(t0)); // Signed comparison. - - // Out of stack space. - __ lw(a1, MemOperand(fp, kFunctionOffset)); - __ push(a1); - __ push(v0); - __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); - // End of stack check. - - // Push current limit and index. - __ bind(&okay); - __ push(v0); // Limit. - __ mov(a1, zero_reg); // Initial index. - __ push(a1); - - // Change context eagerly to get the right global object if necessary. - __ lw(a0, MemOperand(fp, kFunctionOffset)); - __ lw(cp, FieldMemOperand(a0, JSFunction::kContextOffset)); - // Load the shared function info while the function is still in a0. - __ lw(a1, FieldMemOperand(a0, JSFunction::kSharedFunctionInfoOffset)); - - // Compute the receiver. - Label call_to_object, use_global_receiver, push_receiver; - __ lw(a0, MemOperand(fp, kRecvOffset)); - - // Do not transform the receiver for strict mode functions. - __ lw(a2, FieldMemOperand(a1, SharedFunctionInfo::kCompilerHintsOffset)); - __ And(t0, a2, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + - kSmiTagSize))); - __ Branch(&push_receiver, ne, t0, Operand(zero_reg)); - - // Do not transform the receiver for native (Compilerhints already in a2). - __ And(t0, a2, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); - __ Branch(&push_receiver, ne, t0, Operand(zero_reg)); - - // Compute the receiver in non-strict mode. - __ And(t0, a0, Operand(kSmiTagMask)); - __ Branch(&call_to_object, eq, t0, Operand(zero_reg)); - __ LoadRoot(a1, Heap::kNullValueRootIndex); - __ Branch(&use_global_receiver, eq, a0, Operand(a1)); - __ LoadRoot(a2, Heap::kUndefinedValueRootIndex); - __ Branch(&use_global_receiver, eq, a0, Operand(a2)); - - // Check if the receiver is already a JavaScript object. - // a0: receiver - STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); - __ GetObjectType(a0, a1, a1); - __ Branch(&push_receiver, ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); - - // Convert the receiver to a regular object. - // a0: receiver - __ bind(&call_to_object); - __ push(a0); - __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); - __ mov(a0, v0); // Put object in a0 to match other paths to push_receiver. - __ Branch(&push_receiver); - - // Use the current global receiver object as the receiver. - __ bind(&use_global_receiver); - const int kGlobalOffset = - Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; - __ lw(a0, FieldMemOperand(cp, kGlobalOffset)); - __ lw(a0, FieldMemOperand(a0, GlobalObject::kGlobalContextOffset)); - __ lw(a0, FieldMemOperand(a0, kGlobalOffset)); - __ lw(a0, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset)); - - // Push the receiver. - // a0: receiver - __ bind(&push_receiver); - __ push(a0); - - // Copy all arguments from the array to the stack. - Label entry, loop; - __ lw(a0, MemOperand(fp, kIndexOffset)); - __ Branch(&entry); + { + FrameScope frame_scope(masm, StackFrame::INTERNAL); + __ lw(a0, MemOperand(fp, kFunctionOffset)); // Get the function. + __ push(a0); + __ lw(a0, MemOperand(fp, kArgsOffset)); // Get the args array. + __ push(a0); + // Returns (in v0) number of arguments to copy to stack as Smi. + __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); + + // Check the stack for overflow. We are not trying to catch + // interruptions (e.g. debug break and preemption) here, so the "real stack + // limit" is checked. + Label okay; + __ LoadRoot(a2, Heap::kRealStackLimitRootIndex); + // Make a2 the space we have left. The stack might already be overflowed + // here which will cause a2 to become negative. + __ subu(a2, sp, a2); + // Check if the arguments will overflow the stack. + __ sll(t3, v0, kPointerSizeLog2 - kSmiTagSize); + __ Branch(&okay, gt, a2, Operand(t3)); // Signed comparison. + + // Out of stack space. + __ lw(a1, MemOperand(fp, kFunctionOffset)); + __ push(a1); + __ push(v0); + __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); + // End of stack check. + + // Push current limit and index. + __ bind(&okay); + __ push(v0); // Limit. + __ mov(a1, zero_reg); // Initial index. + __ push(a1); - // Load the current argument from the arguments array and push it to the - // stack. - // a0: current argument index - __ bind(&loop); - __ lw(a1, MemOperand(fp, kArgsOffset)); - __ push(a1); - __ push(a0); + // Get the receiver. + __ lw(a0, MemOperand(fp, kRecvOffset)); - // Call the runtime to access the property in the arguments array. - __ CallRuntime(Runtime::kGetProperty, 2); - __ push(v0); + // Check that the function is a JS function (otherwise it must be a proxy). + Label push_receiver; + __ lw(a1, MemOperand(fp, kFunctionOffset)); + __ GetObjectType(a1, a2, a2); + __ Branch(&push_receiver, ne, a2, Operand(JS_FUNCTION_TYPE)); - // Use inline caching to access the arguments. - __ lw(a0, MemOperand(fp, kIndexOffset)); - __ Addu(a0, a0, Operand(1 << kSmiTagSize)); - __ sw(a0, MemOperand(fp, kIndexOffset)); + // Change context eagerly to get the right global object if necessary. + __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); + // Load the shared function info while the function is still in a1. + __ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); - // Test if the copy loop has finished copying all the elements from the - // arguments object. - __ bind(&entry); - __ lw(a1, MemOperand(fp, kLimitOffset)); - __ Branch(&loop, ne, a0, Operand(a1)); - // Invoke the function. - ParameterCount actual(a0); - __ sra(a0, a0, kSmiTagSize); - __ lw(a1, MemOperand(fp, kFunctionOffset)); - __ InvokeFunction(a1, actual, CALL_FUNCTION, - NullCallWrapper(), CALL_AS_METHOD); - - // Tear down the internal frame and remove function, receiver and args. - __ LeaveInternalFrame(); - __ Addu(sp, sp, Operand(3 * kPointerSize)); - __ Ret(); + // Compute the receiver. + // Do not transform the receiver for strict mode functions. + Label call_to_object, use_global_receiver; + __ lw(a2, FieldMemOperand(a2, SharedFunctionInfo::kCompilerHintsOffset)); + __ And(t3, a2, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + + kSmiTagSize))); + __ Branch(&push_receiver, ne, t3, Operand(zero_reg)); + + // Do not transform the receiver for native (Compilerhints already in a2). + __ And(t3, a2, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); + __ Branch(&push_receiver, ne, t3, Operand(zero_reg)); + + // Compute the receiver in non-strict mode. + __ And(t3, a0, Operand(kSmiTagMask)); + __ Branch(&call_to_object, eq, t3, Operand(zero_reg)); + __ LoadRoot(a1, Heap::kNullValueRootIndex); + __ Branch(&use_global_receiver, eq, a0, Operand(a1)); + __ LoadRoot(a2, Heap::kUndefinedValueRootIndex); + __ Branch(&use_global_receiver, eq, a0, Operand(a2)); + + // Check if the receiver is already a JavaScript object. + // a0: receiver + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + __ GetObjectType(a0, a1, a1); + __ Branch(&push_receiver, ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); + + // Convert the receiver to a regular object. + // a0: receiver + __ bind(&call_to_object); + __ push(a0); + __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); + __ mov(a0, v0); // Put object in a0 to match other paths to push_receiver. + __ Branch(&push_receiver); + + // Use the current global receiver object as the receiver. + __ bind(&use_global_receiver); + const int kGlobalOffset = + Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; + __ lw(a0, FieldMemOperand(cp, kGlobalOffset)); + __ lw(a0, FieldMemOperand(a0, GlobalObject::kGlobalContextOffset)); + __ lw(a0, FieldMemOperand(a0, kGlobalOffset)); + __ lw(a0, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset)); + + // Push the receiver. + // a0: receiver + __ bind(&push_receiver); + __ push(a0); + + // Copy all arguments from the array to the stack. + Label entry, loop; + __ lw(a0, MemOperand(fp, kIndexOffset)); + __ Branch(&entry); + + // Load the current argument from the arguments array and push it to the + // stack. + // a0: current argument index + __ bind(&loop); + __ lw(a1, MemOperand(fp, kArgsOffset)); + __ push(a1); + __ push(a0); + + // Call the runtime to access the property in the arguments array. + __ CallRuntime(Runtime::kGetProperty, 2); + __ push(v0); + + // Use inline caching to access the arguments. + __ lw(a0, MemOperand(fp, kIndexOffset)); + __ Addu(a0, a0, Operand(1 << kSmiTagSize)); + __ sw(a0, MemOperand(fp, kIndexOffset)); + + // Test if the copy loop has finished copying all the elements from the + // arguments object. + __ bind(&entry); + __ lw(a1, MemOperand(fp, kLimitOffset)); + __ Branch(&loop, ne, a0, Operand(a1)); + + // Invoke the function. + Label call_proxy; + ParameterCount actual(a0); + __ sra(a0, a0, kSmiTagSize); + __ lw(a1, MemOperand(fp, kFunctionOffset)); + __ GetObjectType(a1, a2, a2); + __ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE)); + + __ InvokeFunction(a1, actual, CALL_FUNCTION, + NullCallWrapper(), CALL_AS_METHOD); + + frame_scope.GenerateLeaveFrame(); + __ Ret(USE_DELAY_SLOT); + __ Addu(sp, sp, Operand(3 * kPointerSize)); // In delay slot. + + // Invoke the function proxy. + __ bind(&call_proxy); + __ push(a1); // Add function proxy as last argument. + __ Addu(a0, a0, Operand(1)); + __ li(a2, Operand(0, RelocInfo::NONE)); + __ SetCallKind(t1, CALL_AS_METHOD); + __ GetBuiltinEntry(a3, Builtins::CALL_FUNCTION_PROXY); + __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), + RelocInfo::CODE_TARGET); + + // Tear down the internal frame and remove function, receiver and args. + } + + __ Ret(USE_DELAY_SLOT); + __ Addu(sp, sp, Operand(3 * kPointerSize)); // In delay slot. } |