| Index: src/arm/builtins-arm.cc
|
| diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
|
| index e4a1a33abe47e51d1ba5a52cf354704af16dcef1..78d37e9c7470e0db13fafe163369fb5aadbba125 100644
|
| --- a/src/arm/builtins-arm.cc
|
| +++ b/src/arm/builtins-arm.cc
|
| @@ -499,7 +499,10 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
|
| // r0: number of arguments
|
| // r1: called object
|
| __ bind(&non_function_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.
|
| + __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
|
| // Set expected number of arguments to zero (not changing r0).
|
| __ mov(r2, Operand(0));
|
| __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
|
| @@ -904,7 +907,7 @@ void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
|
|
|
| void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
| // 1. Make sure we have at least one argument.
|
| - // r0: actual number of argument
|
| + // r0: actual number of arguments
|
| { Label done;
|
| __ tst(r0, Operand(r0));
|
| __ b(ne, &done);
|
| @@ -914,40 +917,34 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
| __ bind(&done);
|
| }
|
|
|
| - // 2. Get the function to call from the stack.
|
| + // 2. Get the function to call (passed as receiver) from the stack, check
|
| + // if it is a function.
|
| // r0: actual number of arguments
|
| - { Label done, non_function, function;
|
| + Label non_function;
|
| + { Label function;
|
| __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
|
| __ tst(r1, Operand(kSmiTagMask));
|
| __ b(eq, &non_function);
|
| __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
|
| - __ b(eq, &function);
|
| -
|
| - // Non-function called: Clear the function to force exception.
|
| - __ bind(&non_function);
|
| - __ mov(r1, Operand(0));
|
| - __ b(&done);
|
| -
|
| - // Change the context eagerly because it will be used below to get the
|
| - // right global object.
|
| + __ b(ne, &non_function);
|
| __ bind(&function);
|
| - __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
|
| -
|
| - __ bind(&done);
|
| }
|
|
|
| - // 3. Make sure first argument is an object; convert if necessary.
|
| + // 3a. Patch the first argument if necessary when calling a function.
|
| // r0: actual number of arguments
|
| // r1: function
|
| - { Label call_to_object, use_global_receiver, patch_receiver, done;
|
| + Label shift_arguments;
|
| + { Label convert_to_object, use_global_receiver, patch_receiver;
|
| + // Change context eagerly in case we need the global receiver.
|
| + __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
|
| +
|
| __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
|
| __ ldr(r2, MemOperand(r2, -kPointerSize));
|
| -
|
| // r0: actual number of arguments
|
| // r1: function
|
| // r2: first argument
|
| __ tst(r2, Operand(kSmiTagMask));
|
| - __ b(eq, &call_to_object);
|
| + __ b(eq, &convert_to_object);
|
|
|
| __ LoadRoot(r3, Heap::kNullValueRootIndex);
|
| __ cmp(r2, r3);
|
| @@ -957,31 +954,28 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
| __ b(eq, &use_global_receiver);
|
|
|
| __ CompareObjectType(r2, r3, r3, FIRST_JS_OBJECT_TYPE);
|
| - __ b(lt, &call_to_object);
|
| + __ b(lt, &convert_to_object);
|
| __ cmp(r3, Operand(LAST_JS_OBJECT_TYPE));
|
| - __ b(le, &done);
|
| + __ b(le, &shift_arguments);
|
|
|
| - __ bind(&call_to_object);
|
| - __ EnterInternalFrame();
|
| -
|
| - // Store number of arguments and function across the call into the runtime.
|
| - __ mov(r0, Operand(r0, LSL, kSmiTagSize));
|
| + __ bind(&convert_to_object);
|
| + __ EnterInternalFrame(); // In order to preserve argument count.
|
| + __ mov(r0, Operand(r0, LSL, kSmiTagSize)); // Smi-tagged.
|
| __ push(r0);
|
| - __ push(r1);
|
|
|
| __ push(r2);
|
| __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
|
| __ mov(r2, r0);
|
|
|
| - // Restore number of arguments and function.
|
| - __ pop(r1);
|
| __ pop(r0);
|
| __ mov(r0, Operand(r0, ASR, kSmiTagSize));
|
| -
|
| __ LeaveInternalFrame();
|
| - __ b(&patch_receiver);
|
| + // Restore the function to r1.
|
| + __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
|
| + __ jmp(&patch_receiver);
|
|
|
| - // Use the global receiver object from the called function as the receiver.
|
| + // Use the global receiver object from the called function as the
|
| + // receiver.
|
| __ bind(&use_global_receiver);
|
| const int kGlobalIndex =
|
| Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
|
| @@ -994,27 +988,27 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
| __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2));
|
| __ str(r2, MemOperand(r3, -kPointerSize));
|
|
|
| - __ bind(&done);
|
| + __ jmp(&shift_arguments);
|
| }
|
|
|
| - // 4. Handle non-functions.
|
| - // r0: actual number of arguments (including call() receiver)
|
| + // 3b. 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.
|
| + // r0: actual number of arguments
|
| // r1: function
|
| - { Label done;
|
| - __ tst(r1, r1);
|
| - __ b(ne, &done);
|
| - __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION
|
| - // Transfer the receiver from the first argument to the top of the
|
| - // caller's expression stack simply by decrementing argc.
|
| - __ sub(r0, r0, Operand(1));
|
| - __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
|
| - __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
|
| - RelocInfo::CODE_TARGET);
|
| - __ bind(&done);
|
| - }
|
| -
|
| - // 5. Shift arguments one slot toward the bottom of the
|
| - // stack, overwriting the receiver.
|
| + __ bind(&non_function);
|
| + __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
|
| + __ str(r1, MemOperand(r2, -kPointerSize));
|
| + // Clear r1 to indicate a non-function being called.
|
| + __ mov(r1, Operand(0));
|
| +
|
| + // 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.
|
| + // r0: actual number of arguments
|
| + // r1: function
|
| + __ bind(&shift_arguments);
|
| { Label loop;
|
| // Calculate the copy start address (destination). Copy end address is sp.
|
| __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
|
| @@ -1025,14 +1019,28 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
| __ sub(r2, r2, Operand(kPointerSize));
|
| __ cmp(r2, sp);
|
| __ b(ne, &loop);
|
| - // Adjust the actual number of arguments and remove the top element.
|
| + // Adjust the actual number of arguments and remove the top element
|
| + // (which is a copy of the last argument).
|
| __ sub(r0, r0, Operand(1));
|
| __ pop();
|
| }
|
|
|
| - // 6. Get the code for the function or the non-function builtin.
|
| - // If number of expected arguments matches, then call. Otherwise restart
|
| - // the arguments adaptor stub.
|
| + // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
|
| + // r0: actual number of arguments
|
| + // r1: function
|
| + { Label function;
|
| + __ tst(r1, r1);
|
| + __ b(ne, &function);
|
| + __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION
|
| + __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
|
| + __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
|
| + RelocInfo::CODE_TARGET);
|
| + __ bind(&function);
|
| + }
|
| +
|
| + // 5b. Get the code to call from the function and check that the number of
|
| + // expected arguments matches what we're providing. If so, jump
|
| + // (tail-call) to the code in register edx without checking arguments.
|
| // r0: actual number of arguments
|
| // r1: function
|
| __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
| @@ -1044,7 +1052,6 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
| __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
|
| RelocInfo::CODE_TARGET, ne);
|
|
|
| - // 7. Jump (tail-call) to the code in r3 without checking arguments.
|
| ParameterCount expected(0);
|
| __ InvokeCode(r3, expected, expected, JUMP_FUNCTION);
|
| }
|
|
|