[builtins] Unify the various versions of [[Call]] with a Call builtin.
authorbmeurer <bmeurer@chromium.org>
Tue, 8 Sep 2015 07:50:22 +0000 (00:50 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 8 Sep 2015 07:50:34 +0000 (07:50 +0000)
The new Call and CallFunction builtins supersede the current
CallFunctionStub (and CallIC magic) and will be the single bottleneck
for all calling, including the currently special Function.prototype.call
and Function.prototype.apply builtins, which had handwritten (and
not fully compliant) versions of CallFunctionStub, and also the
CallIC(s), which where also slightly different.

This also reduces the overhead for API function calls, which is still
unnecessary high, but let's do that step-by-step.

This also fixes a bunch of cases where the implicit ToObject for
sloppy receivers was done in the wrong context (in the caller
context instead of the callee context), which basically meant
that we allowed cross context access to %ObjectPrototype%.

MIPS and MIPS64 ports contributed by akos.palfi@imgtec.com.

R=mstarzinger@chromium.org, jarin@chromium.org, mvstanton@chromium.org
CQ_INCLUDE_TRYBOTS=tryserver.v8:v8_linux_layout_dbg,v8_linux_nosnap_dbg
BUG=v8:4413
LOG=n

Committed: https://crrev.com/ef268a83be4dead004047c25b702319ea4be7277
Cr-Commit-Position: refs/heads/master@{#30627}

Review URL: https://codereview.chromium.org/1311013008

Cr-Commit-Position: refs/heads/master@{#30629}

33 files changed:
src/arm/builtins-arm.cc
src/arm/code-stubs-arm.cc
src/arm/macro-assembler-arm.cc
src/arm/macro-assembler-arm.h
src/arm64/builtins-arm64.cc
src/arm64/code-stubs-arm64.cc
src/arm64/macro-assembler-arm64.cc
src/arm64/macro-assembler-arm64.h
src/bailout-reason.h
src/builtins.h
src/code-stubs.h
src/contexts.h
src/ia32/assembler-ia32.cc
src/ia32/assembler-ia32.h
src/ia32/builtins-ia32.cc
src/ia32/code-stubs-ia32.cc
src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/mips/builtins-mips.cc
src/mips/code-stubs-mips.cc
src/mips/macro-assembler-mips.cc
src/mips/macro-assembler-mips.h
src/mips64/builtins-mips64.cc
src/mips64/code-stubs-mips64.cc
src/mips64/macro-assembler-mips64.cc
src/mips64/macro-assembler-mips64.h
src/objects.h
src/runtime.js
src/runtime/runtime-function.cc
src/x64/builtins-x64.cc
src/x64/code-stubs-x64.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h

index ab2d77e2898e7a9107925736cff15afd2e87c360..f63e05f2cff7533d12d9a80d71780fd0fe88428f 100644 (file)
@@ -1256,127 +1256,30 @@ void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
 }
 
 
 }
 
 
+// static
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
   // 1. Make sure we have at least one argument.
   // r0: actual number of arguments
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
   // 1. Make sure we have at least one argument.
   // r0: actual number of arguments
-  { Label done;
+  {
+    Label done;
     __ cmp(r0, Operand::Zero());
     __ b(ne, &done);
     __ cmp(r0, Operand::Zero());
     __ b(ne, &done);
-    __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
-    __ push(r2);
+    __ PushRoot(Heap::kUndefinedValueRootIndex);
     __ add(r0, r0, Operand(1));
     __ bind(&done);
   }
 
     __ add(r0, r0, Operand(1));
     __ bind(&done);
   }
 
-  // 2. Get the function to call (passed as receiver) from the stack, check
-  //    if it is a function.
+  // 2. Get the callable to call (passed as receiver) from the stack.
   // r0: actual number of arguments
   // r0: actual number of arguments
-  Label slow, non_function;
   __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
   __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
-  __ JumpIfSmi(r1, &non_function);
-  __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
-  __ b(ne, &slow);
-
-  // 3a. Patch the first argument if necessary when calling a function.
-  // r0: actual number of arguments
-  // r1: function
-  Label shift_arguments;
-  __ mov(r4, Operand::Zero());  // indicate regular JS_FUNCTION
-  { Label convert_to_object, use_global_proxy, patch_receiver;
-    // Change context eagerly in case we need the global receiver.
-    __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
-
-    // Do not transform the receiver for strict mode functions.
-    __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
-    __ ldr(r3, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset));
-    __ tst(r3, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
-                             kSmiTagSize)));
-    __ b(ne, &shift_arguments);
-
-    // Do not transform the receiver for native (Compilerhints already in r3).
-    __ tst(r3, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
-    __ b(ne, &shift_arguments);
-
-    // Compute the receiver in sloppy mode.
-    __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
-    __ ldr(r2, MemOperand(r2, -kPointerSize));
-    // r0: actual number of arguments
-    // r1: function
-    // r2: first argument
-    __ JumpIfSmi(r2, &convert_to_object);
-
-    __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
-    __ cmp(r2, r3);
-    __ b(eq, &use_global_proxy);
-    __ LoadRoot(r3, Heap::kNullValueRootIndex);
-    __ cmp(r2, r3);
-    __ b(eq, &use_global_proxy);
-
-    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
-    __ CompareObjectType(r2, r3, r3, FIRST_SPEC_OBJECT_TYPE);
-    __ b(ge, &shift_arguments);
-
-    __ bind(&convert_to_object);
-
-    {
-      // Enter an internal frame in order to preserve argument count.
-      FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
-      __ SmiTag(r0);
-      __ push(r0);
-
-      __ mov(r0, r2);
-      ToObjectStub stub(masm->isolate());
-      __ CallStub(&stub);
-      __ mov(r2, r0);
-
-      __ pop(r0);
-      __ SmiUntag(r0);
-
-      // Exit the internal frame.
-    }
-
-    // Restore the function to r1, and the flag to r4.
-    __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
-    __ mov(r4, Operand::Zero());
-    __ jmp(&patch_receiver);
 
 
-    __ bind(&use_global_proxy);
-  __ ldr(r2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
-  __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalProxyOffset));
-
-    __ bind(&patch_receiver);
-    __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2));
-    __ str(r2, MemOperand(r3, -kPointerSize));
-
-    __ jmp(&shift_arguments);
-  }
-
-  // 3b. Check for function proxy.
-  __ bind(&slow);
-  __ mov(r4, Operand(1, RelocInfo::NONE32));  // indicate function proxy
-  __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE));
-  __ b(eq, &shift_arguments);
-  __ bind(&non_function);
-  __ mov(r4, Operand(2, RelocInfo::NONE32));  // 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.
-  // r0: actual number of arguments
-  // r1: function
-  // r4: call type (0: JS function, 1: function proxy, 2: non-function)
-  __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
-  __ str(r1, MemOperand(r2, -kPointerSize));
-
-  // 4. Shift arguments and return address one slot down on the stack
+  // 3. 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
   //    (overwriting the original receiver).  Adjust argument count to make
   //    the original first argument the new receiver.
   // r0: actual number of arguments
-  // r1: function
-  // r4: call type (0: JS function, 1: function proxy, 2: non-function)
-  __ bind(&shift_arguments);
-  { Label loop;
+  // r1: callable
+  {
+    Label loop;
     // Calculate the copy start address (destination). Copy end address is sp.
     __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
 
     // Calculate the copy start address (destination). Copy end address is sp.
     __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
 
@@ -1392,49 +1295,8 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
     __ pop();
   }
 
     __ pop();
   }
 
-  // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
-  //     or a function proxy via CALL_FUNCTION_PROXY.
-  // r0: actual number of arguments
-  // r1: function
-  // r4: call type (0: JS function, 1: function proxy, 2: non-function)
-  { Label function, non_proxy;
-    __ tst(r4, r4);
-    __ b(eq, &function);
-    // Expected number of arguments is 0 for CALL_NON_FUNCTION.
-    __ mov(r2, Operand::Zero());
-    __ cmp(r4, Operand(1));
-    __ b(ne, &non_proxy);
-
-    __ push(r1);  // re-add proxy object as additional argument
-    __ add(r0, r0, Operand(1));
-    __ GetBuiltinFunction(r1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-            RelocInfo::CODE_TARGET);
-
-    __ bind(&non_proxy);
-    __ GetBuiltinFunction(r1, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-    __ Jump(masm->isolate()->builtins()->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));
-  __ ldr(r2,
-         FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset));
-  __ SmiUntag(r2);
-  __ cmp(r2, r0);  // Check formal and actual parameter counts.
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET,
-          ne);
-
-  __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
-  ParameterCount expected(0);
-  __ InvokeCode(r3, expected, expected, JUMP_FUNCTION, NullCallWrapper());
+  // 4. Call the callable.
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -1499,9 +1361,8 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
     const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
     __ ldr(r0, MemOperand(fp, kFunctionOffset));  // get the function
     const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
     __ ldr(r0, MemOperand(fp, kFunctionOffset));  // get the function
-    __ push(r0);
-    __ ldr(r0, MemOperand(fp, kArgumentsOffset));  // get the args array
-    __ push(r0);
+    __ ldr(r1, MemOperand(fp, kArgumentsOffset));  // get the args array
+    __ Push(r0, r1);
     if (targetIsArgument) {
       __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX,
                        CALL_FUNCTION);
     if (targetIsArgument) {
       __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX,
                        CALL_FUNCTION);
@@ -1516,91 +1377,18 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
         StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
     const int kLimitOffset =
         StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
         StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
     const int kLimitOffset =
         StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
-    __ push(r0);  // limit
-    __ mov(r1, Operand::Zero());  // initial index
-    __ push(r1);
-
-    // Get the receiver.
-    __ ldr(r0, MemOperand(fp, kReceiverOffset));
-
-    // Check that the function is a JS function (otherwise it must be a proxy).
-    Label push_receiver;
-    __ ldr(r1, MemOperand(fp, kFunctionOffset));
-    __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
-    __ b(ne, &push_receiver);
-
-    // Change context eagerly to get the right global object if necessary.
-    __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
-    // Load the shared function info while the function is still in r1.
-    __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
-
-    // Compute the receiver.
-    // Do not transform the receiver for strict mode functions.
-    Label call_to_object, use_global_proxy;
-    __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset));
-    __ tst(r2, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
-                             kSmiTagSize)));
-    __ b(ne, &push_receiver);
-
-    // Do not transform the receiver for strict mode functions.
-    __ tst(r2, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
-    __ b(ne, &push_receiver);
-
-    // Compute the receiver in sloppy mode.
-    __ JumpIfSmi(r0, &call_to_object);
-    __ LoadRoot(r1, Heap::kNullValueRootIndex);
-    __ cmp(r0, r1);
-    __ b(eq, &use_global_proxy);
-    __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
-    __ cmp(r0, r1);
-    __ b(eq, &use_global_proxy);
-
-    // Check if the receiver is already a JavaScript object.
-    // r0: receiver
-    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
-    __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
-    __ b(ge, &push_receiver);
-
-    // Convert the receiver to a regular object.
-    // r0: receiver
-    __ bind(&call_to_object);
-    ToObjectStub stub(masm->isolate());
-    __ CallStub(&stub);
-    __ b(&push_receiver);
-
-    __ bind(&use_global_proxy);
-    __ ldr(r0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
-    __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalProxyOffset));
-
-    // Push the receiver.
-    // r0: receiver
-    __ bind(&push_receiver);
-    __ push(r0);
+    __ mov(r1, Operand::Zero());
+    __ ldr(r2, MemOperand(fp, kReceiverOffset));
+    __ Push(r0, r1, r2);  // limit, initial index and receiver.
 
     // Copy all arguments from the array to the stack.
 
     // Copy all arguments from the array to the stack.
-    Generate_PushAppliedArguments(
-        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+    Generate_PushAppliedArguments(masm, kArgumentsOffset, kIndexOffset,
+                                  kLimitOffset);
 
 
-    // Call the function.
-    Label call_proxy;
-    ParameterCount actual(r0);
+    // Call the callable.
+    // TODO(bmeurer): This should be a tail call according to ES6.
     __ ldr(r1, MemOperand(fp, kFunctionOffset));
     __ ldr(r1, MemOperand(fp, kFunctionOffset));
-    __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
-    __ b(ne, &call_proxy);
-    __ InvokeFunction(r1, actual, CALL_FUNCTION, NullCallWrapper());
-
-    frame_scope.GenerateLeaveFrame();
-    __ add(sp, sp, Operand(kStackSize * kPointerSize));
-    __ Jump(lr);
-
-    // Call the function proxy.
-    __ bind(&call_proxy);
-    __ push(r1);  // add function proxy as last argument
-    __ add(r0, r0, Operand(1));
-    __ mov(r2, Operand::Zero());
-    __ GetBuiltinFunction(r1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-            RelocInfo::CODE_TARGET);
+    __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 
     // Tear down the internal frame and remove function, receiver and args.
   }
 
     // Tear down the internal frame and remove function, receiver and args.
   }
@@ -1733,6 +1521,141 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
 }
 
 
 }
 
 
+// static
+void Builtins::Generate_CallFunction(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r0 : the number of arguments (not including the receiver)
+  //  -- r1 : the function to call (checked to be a JSFunction)
+  // -----------------------------------
+
+  Label convert, convert_global_proxy, convert_to_object, done_convert;
+  __ AssertFunction(r1);
+  // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal
+  // slot is "classConstructor".
+  // Enter the context of the function; ToObject has to run in the function
+  // context, and we also need to take the global proxy from the function
+  // context in case of conversion.
+  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
+  STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
+                SharedFunctionInfo::kStrictModeByteOffset);
+  __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
+  __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+  // We need to convert the receiver for non-native sloppy mode functions.
+  __ ldrb(r3, FieldMemOperand(r2, SharedFunctionInfo::kNativeByteOffset));
+  __ tst(r3, Operand((1 << SharedFunctionInfo::kNativeBitWithinByte) |
+                     (1 << SharedFunctionInfo::kStrictModeBitWithinByte)));
+  __ b(ne, &done_convert);
+  {
+    __ ldr(r3, MemOperand(sp, r0, LSL, kPointerSizeLog2));
+
+    // ----------- S t a t e -------------
+    //  -- r0 : the number of arguments (not including the receiver)
+    //  -- r1 : the function to call (checked to be a JSFunction)
+    //  -- r2 : the shared function info.
+    //  -- r3 : the receiver
+    //  -- cp : the function context.
+    // -----------------------------------
+
+    Label convert_receiver;
+    __ JumpIfSmi(r3, &convert_to_object);
+    STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+    __ CompareObjectType(r3, r4, r4, FIRST_JS_RECEIVER_TYPE);
+    __ b(hs, &done_convert);
+    __ JumpIfRoot(r3, Heap::kUndefinedValueRootIndex, &convert_global_proxy);
+    __ JumpIfNotRoot(r3, Heap::kNullValueRootIndex, &convert_to_object);
+    __ bind(&convert_global_proxy);
+    {
+      // Patch receiver to global proxy.
+      __ LoadGlobalProxy(r3);
+    }
+    __ b(&convert_receiver);
+    __ bind(&convert_to_object);
+    {
+      // Convert receiver using ToObject.
+      // TODO(bmeurer): Inline the allocation here to avoid building the frame
+      // in the fast case? (fall back to AllocateInNewSpace?)
+      FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+      __ SmiTag(r0);
+      __ Push(r0, r1);
+      __ mov(r0, r3);
+      ToObjectStub stub(masm->isolate());
+      __ CallStub(&stub);
+      __ mov(r3, r0);
+      __ Pop(r0, r1);
+      __ SmiUntag(r0);
+    }
+    __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+    __ bind(&convert_receiver);
+    __ str(r3, MemOperand(sp, r0, LSL, kPointerSizeLog2));
+  }
+  __ bind(&done_convert);
+
+  // ----------- S t a t e -------------
+  //  -- r0 : the number of arguments (not including the receiver)
+  //  -- r1 : the function to call (checked to be a JSFunction)
+  //  -- r2 : the shared function info.
+  //  -- cp : the function context.
+  // -----------------------------------
+
+  __ ldr(r2,
+         FieldMemOperand(r2, SharedFunctionInfo::kFormalParameterCountOffset));
+  __ SmiUntag(r2);
+  __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
+  ParameterCount actual(r0);
+  ParameterCount expected(r2);
+  __ InvokeCode(r3, expected, actual, JUMP_FUNCTION, NullCallWrapper());
+}
+
+
+// static
+void Builtins::Generate_Call(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r0 : the number of arguments (not including the receiver)
+  //  -- r1 : the target to call (can be any Object).
+  // -----------------------------------
+
+  Label non_smi, non_function;
+  __ JumpIfSmi(r1, &non_function);
+  __ bind(&non_smi);
+  __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
+          eq);
+  __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE));
+  __ b(ne, &non_function);
+
+  // 1. Call to function proxy.
+  // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
+  __ ldr(r1, FieldMemOperand(r1, JSFunctionProxy::kCallTrapOffset));
+  __ AssertNotSmi(r1);
+  __ b(&non_smi);
+
+  // 2. Call to something else, which might have a [[Call]] internal method (if
+  // not we raise an exception).
+  __ bind(&non_function);
+  // TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
+  // be awesome instead; i.e. a trivial improvement would be to call into the
+  // runtime and just deal with the API function there instead of returning a
+  // delegate from a runtime call that just jumps back to the runtime once
+  // called. Or, bonus points, call directly into the C API function here, as
+  // we do in some Crankshaft fast cases.
+  // Overwrite the original receiver with the (original) target.
+  __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
+  {
+    // Determine the delegate for the target (if any).
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    __ SmiTag(r0);
+    __ Push(r0, r1);
+    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
+    __ mov(r1, r0);
+    __ Pop(r0);
+    __ SmiUntag(r0);
+  }
+  // The delegate is always a regular function.
+  __ AssertFunction(r1);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+}
+
+
 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- r0 : actual number of arguments
 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- r0 : actual number of arguments
index f504b72fef7a3791c5ad590ddd25dbfc28fade25..af86e47a35f44bbca7559429624caa40e2af2242 100644 (file)
@@ -2395,31 +2395,9 @@ static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
 }
 
 
 }
 
 
-static void EmitSlowCase(MacroAssembler* masm,
-                         int argc,
-                         Label* non_function) {
-  // Check for function proxy.
-  __ cmp(r4, Operand(JS_FUNCTION_PROXY_TYPE));
-  __ b(ne, non_function);
-  __ push(r1);  // put proxy as additional argument
-  __ mov(r0, Operand(argc + 1, RelocInfo::NONE32));
-  __ mov(r2, Operand::Zero());
-  __ GetBuiltinFunction(r1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-  {
-    Handle<Code> adaptor =
-        masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
-    __ Jump(adaptor, RelocInfo::CODE_TARGET);
-  }
-
-  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
-  // of the original receiver from the call site).
-  __ bind(non_function);
-  __ str(r1, MemOperand(sp, argc * kPointerSize));
-  __ mov(r0, Operand(argc));  // Set up the number of arguments.
-  __ mov(r2, Operand::Zero());
-  __ GetBuiltinFunction(r1, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET);
+static void EmitSlowCase(MacroAssembler* masm, int argc) {
+  __ mov(r0, Operand(argc));
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -2441,12 +2419,12 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
                                    int argc, bool needs_checks,
                                    bool call_as_method) {
   // r1 : the function to call
                                    int argc, bool needs_checks,
                                    bool call_as_method) {
   // r1 : the function to call
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
 
   if (needs_checks) {
     // Check that the function is really a JavaScript function.
     // r1: pushed function (to be verified)
 
   if (needs_checks) {
     // Check that the function is really a JavaScript function.
     // r1: pushed function (to be verified)
-    __ JumpIfSmi(r1, &non_function);
+    __ JumpIfSmi(r1, &slow);
 
     // Goto slow case if we do not have a function.
     __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE);
 
     // Goto slow case if we do not have a function.
     __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE);
@@ -2481,7 +2459,7 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ bind(&slow);
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ bind(&slow);
-    EmitSlowCase(masm, argc, &non_function);
+    EmitSlowCase(masm, argc);
   }
 
   if (call_as_method) {
   }
 
   if (call_as_method) {
@@ -2615,13 +2593,8 @@ void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
-  CallFunctionNoFeedback(masm,
-                         arg_count(),
-                         true,
-                         CallAsMethod());
-
-  // Unreachable.
-  __ stop("Unexpected code address");
+  __ mov(r0, Operand(arg_count()));
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -2634,7 +2607,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
   Label have_js_function;
   int argc = arg_count();
   ParameterCount actual(argc);
   Label have_js_function;
   int argc = arg_count();
   ParameterCount actual(argc);
@@ -2688,7 +2661,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   __ InvokeFunction(r1, actual, JUMP_FUNCTION, NullCallWrapper());
 
   __ bind(&slow);
   __ InvokeFunction(r1, actual, JUMP_FUNCTION, NullCallWrapper());
 
   __ bind(&slow);
-  EmitSlowCase(masm, argc, &non_function);
+  EmitSlowCase(masm, argc);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
@@ -2775,7 +2748,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   __ bind(&slow_start);
   // Check that the function is really a JavaScript function.
   // r1: pushed function (to be verified)
   __ bind(&slow_start);
   // Check that the function is really a JavaScript function.
   // r1: pushed function (to be verified)
-  __ JumpIfSmi(r1, &non_function);
+  __ JumpIfSmi(r1, &slow);
 
   // Goto slow case if we do not have a function.
   __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE);
 
   // Goto slow case if we do not have a function.
   __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE);
index 057a59cf522fbf89e334d1d618c8c19bb136fccd..3f0ff1aa11da999f622eee4e83d2e6fa2a3e8180 100644 (file)
@@ -2641,6 +2641,12 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
 }
 
 
 }
 
 
+void MacroAssembler::LoadGlobalProxy(Register dst) {
+  ldr(dst, GlobalObjectOperand());
+  ldr(dst, FieldMemOperand(dst, GlobalObject::kGlobalProxyOffset));
+}
+
+
 void MacroAssembler::LoadTransitionedArrayMapConditional(
     ElementsKind expected_kind,
     ElementsKind transitioned_kind,
 void MacroAssembler::LoadTransitionedArrayMapConditional(
     ElementsKind expected_kind,
     ElementsKind transitioned_kind,
@@ -2802,6 +2808,19 @@ void MacroAssembler::AssertName(Register object) {
 }
 
 
 }
 
 
+void MacroAssembler::AssertFunction(Register object) {
+  if (emit_debug_code()) {
+    STATIC_ASSERT(kSmiTag == 0);
+    tst(object, Operand(kSmiTagMask));
+    Check(ne, kOperandIsASmiAndNotAFunction);
+    push(object);
+    CompareObjectType(object, object, object, JS_FUNCTION_TYPE);
+    pop(object);
+    Check(eq, kOperandIsNotAFunction);
+  }
+}
+
+
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
                                                      Register scratch) {
   if (emit_debug_code()) {
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
                                                      Register scratch) {
   if (emit_debug_code()) {
index d4187857402854045c378799b01618e518acdb16..d0f770499c0ad348b1e18e224015e7aac86bb2f7 100644 (file)
@@ -608,6 +608,9 @@ class MacroAssembler: public Assembler {
 
   void LoadContext(Register dst, int context_chain_length);
 
 
   void LoadContext(Register dst, int context_chain_length);
 
+  // Load the global proxy from the current context.
+  void LoadGlobalProxy(Register dst);
+
   // Conditionally load the cached Array transitioned map of type
   // transitioned_kind from the native context if the map in register
   // map_in_out is the cached Array map in the native context of
   // Conditionally load the cached Array transitioned map of type
   // transitioned_kind from the native context if the map in register
   // map_in_out is the cached Array map in the native context of
@@ -947,7 +950,23 @@ class MacroAssembler: public Assembler {
   // Compare the object in a register to a value from the root list.
   // Uses the ip register as scratch.
   void CompareRoot(Register obj, Heap::RootListIndex index);
   // Compare the object in a register to a value from the root list.
   // Uses the ip register as scratch.
   void CompareRoot(Register obj, Heap::RootListIndex index);
+  void PushRoot(Heap::RootListIndex index) {
+    LoadRoot(ip, index);
+    Push(ip);
+  }
+
+  // Compare the object in a register to a value and jump if they are equal.
+  void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal) {
+    CompareRoot(with, index);
+    b(eq, if_equal);
+  }
 
 
+  // Compare the object in a register to a value and jump if they are not equal.
+  void JumpIfNotRoot(Register with, Heap::RootListIndex index,
+                     Label* if_not_equal) {
+    CompareRoot(with, index);
+    b(ne, if_not_equal);
+  }
 
   // Load and check the instance type of an object for being a string.
   // Loads the type into the second argument register.
 
   // Load and check the instance type of an object for being a string.
   // Loads the type into the second argument register.
@@ -1288,6 +1307,9 @@ class MacroAssembler: public Assembler {
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
+  // Abort execution if argument is not a JSFunction, enabled via --debug-code.
+  void AssertFunction(Register object);
+
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object, Register scratch);
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object, Register scratch);
index 2dcfb1bd48afd1913ae0025a50d83195feafc5e3..8297fc3e2bc4d92869a8b9b06c13ee06674355c2 100644 (file)
@@ -1290,21 +1290,15 @@ void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
 
 
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 
 
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
-  enum {
-    call_type_JS_func = 0,
-    call_type_func_proxy = 1,
-    call_type_non_func = 2
-  };
   Register argc = x0;
   Register function = x1;
   Register argc = x0;
   Register function = x1;
-  Register call_type = x4;
   Register scratch1 = x10;
   Register scratch2 = x11;
   Register scratch1 = x10;
   Register scratch2 = x11;
-  Register receiver_type = x13;
 
   ASM_LOCATION("Builtins::Generate_FunctionCall");
   // 1. Make sure we have at least one argument.
 
   ASM_LOCATION("Builtins::Generate_FunctionCall");
   // 1. Make sure we have at least one argument.
-  { Label done;
+  {
+    Label done;
     __ Cbnz(argc, &done);
     __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
     __ Push(scratch1);
     __ Cbnz(argc, &done);
     __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
     __ Push(scratch1);
@@ -1312,107 +1306,14 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
     __ Bind(&done);
   }
 
     __ Bind(&done);
   }
 
-  // 2. Get the function to call (passed as receiver) from the stack, check
-  //    if it is a function.
-  Label slow, non_function;
+  // 2. Get the callable to call (passed as receiver) from the stack.
   __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
   __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
-  __ JumpIfSmi(function, &non_function);
-  __ JumpIfNotObjectType(function, scratch1, receiver_type,
-                         JS_FUNCTION_TYPE, &slow);
-
-  // 3a. Patch the first argument if necessary when calling a function.
-  Label shift_arguments;
-  __ Mov(call_type, static_cast<int>(call_type_JS_func));
-  { Label convert_to_object, use_global_proxy, patch_receiver;
-    // Change context eagerly in case we need the global receiver.
-    __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
-
-    // Do not transform the receiver for strict mode functions.
-    // Also do not transform the receiver for native (Compilerhints already in
-    // x3).
-    __ Ldr(scratch1,
-           FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
-    __ Ldr(scratch2.W(),
-           FieldMemOperand(scratch1, SharedFunctionInfo::kCompilerHintsOffset));
-    __ TestAndBranchIfAnySet(
-        scratch2.W(),
-        (1 << SharedFunctionInfo::kStrictModeFunction) |
-        (1 << SharedFunctionInfo::kNative),
-        &shift_arguments);
-
-    // Compute the receiver in sloppy mode.
-    Register receiver = x2;
-    __ Sub(scratch1, argc, 1);
-    __ Peek(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
-    __ JumpIfSmi(receiver, &convert_to_object);
-
-    __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
-                  &use_global_proxy);
-    __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_proxy);
-
-    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
-    __ JumpIfObjectType(receiver, scratch1, scratch2,
-                        FIRST_SPEC_OBJECT_TYPE, &shift_arguments, ge);
-
-    __ Bind(&convert_to_object);
-
-    {
-      // Enter an internal frame in order to preserve argument count.
-      FrameScope scope(masm, StackFrame::INTERNAL);
-      __ SmiTag(argc);
-
-      __ Push(argc);
-      __ Mov(x0, receiver);
-      ToObjectStub stub(masm->isolate());
-      __ CallStub(&stub);
-      __ Mov(receiver, x0);
-
-      __ Pop(argc);
-      __ SmiUntag(argc);
-
-      // Exit the internal frame.
-    }
-
-    // Restore the function and flag in the registers.
-    __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
-    __ Mov(call_type, static_cast<int>(call_type_JS_func));
-    __ B(&patch_receiver);
-
-    __ Bind(&use_global_proxy);
-    __ Ldr(receiver, GlobalObjectMemOperand());
-    __ Ldr(receiver,
-           FieldMemOperand(receiver, GlobalObject::kGlobalProxyOffset));
 
 
-
-    __ Bind(&patch_receiver);
-    __ Sub(scratch1, argc, 1);
-    __ Poke(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
-
-    __ B(&shift_arguments);
-  }
-
-  // 3b. Check for function proxy.
-  __ Bind(&slow);
-  __ Mov(call_type, static_cast<int>(call_type_func_proxy));
-  __ Cmp(receiver_type, JS_FUNCTION_PROXY_TYPE);
-  __ B(eq, &shift_arguments);
-  __ Bind(&non_function);
-  __ Mov(call_type, static_cast<int>(call_type_non_func));
-
-  // 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.
-  // call type (0: JS function, 1: function proxy, 2: non-function)
-  __ Sub(scratch1, argc, 1);
-  __ Poke(function, Operand(scratch1, LSL, kXRegSizeLog2));
-
-  // 4. Shift arguments and return address one slot down on the stack
+  // 3. 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.
   //    (overwriting the original receiver).  Adjust argument count to make
   //    the original first argument the new receiver.
-  // call type (0: JS function, 1: function proxy, 2: non-function)
-  __ Bind(&shift_arguments);
-  { Label loop;
+  {
+    Label loop;
     // Calculate the copy start address (destination). Copy end address is jssp.
     __ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
     __ Sub(scratch1, scratch2, kPointerSize);
     // Calculate the copy start address (destination). Copy end address is jssp.
     __ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
     __ Sub(scratch1, scratch2, kPointerSize);
@@ -1428,46 +1329,8 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
     __ Drop(1);
   }
 
     __ Drop(1);
   }
 
-  // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
-  //     or a function proxy via CALL_FUNCTION_PROXY.
-  // call type (0: JS function, 1: function proxy, 2: non-function)
-  { Label js_function, non_proxy;
-    __ Cbz(call_type, &js_function);
-    // Expected number of arguments is 0 for CALL_NON_FUNCTION.
-    __ Mov(x2, 0);
-    __ Cmp(call_type, static_cast<int>(call_type_func_proxy));
-    __ B(ne, &non_proxy);
-
-    __ Push(function);  // Re-add proxy object as additional argument.
-    __ Add(argc, argc, 1);
-    __ GetBuiltinFunction(function, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-            RelocInfo::CODE_TARGET);
-
-    __ Bind(&non_proxy);
-    __ GetBuiltinFunction(function, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-    __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-            RelocInfo::CODE_TARGET);
-    __ Bind(&js_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.
-  __ Ldr(x3, FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
-  __ Ldrsw(x2,
-           FieldMemOperand(x3,
-             SharedFunctionInfo::kFormalParameterCountOffset));
-  Label dont_adapt_args;
-  __ Cmp(x2, argc);  // Check formal and actual parameter counts.
-  __ B(eq, &dont_adapt_args);
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET);
-  __ Bind(&dont_adapt_args);
-
-  __ Ldr(x3, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
-  ParameterCount expected(0);
-  __ InvokeCode(x3, expected, expected, JUMP_FUNCTION, NullCallWrapper());
+  // 4. Call the callable.
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -1553,88 +1416,21 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
 
     Generate_CheckStackOverflow(masm, kFunctionOffset, argc, kArgcIsSmiTagged);
 
 
     Generate_CheckStackOverflow(masm, kFunctionOffset, argc, kArgcIsSmiTagged);
 
-    // Push current limit and index.
+    // Push current limit, index and receiver.
     __ Mov(x1, 0);  // Initial index.
     __ Mov(x1, 0);  // Initial index.
-    __ Push(argc, x1);
-
-    Label push_receiver;
     __ Ldr(receiver, MemOperand(fp, kReceiverOffset));
     __ Ldr(receiver, MemOperand(fp, kReceiverOffset));
-
-    // Check that the function is a JS function. Otherwise it must be a proxy.
-    // When it is not the function proxy will be invoked later.
-    __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE,
-                           &push_receiver);
-
-    // Change context eagerly to get the right global object if necessary.
-    __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
-    // Load the shared function info.
-    __ Ldr(x2, FieldMemOperand(function,
-                               JSFunction::kSharedFunctionInfoOffset));
-
-    // Compute and push the receiver.
-    // Do not transform the receiver for strict mode functions.
-    Label convert_receiver_to_object, use_global_proxy;
-    __ Ldr(w10, FieldMemOperand(x2, SharedFunctionInfo::kCompilerHintsOffset));
-    __ Tbnz(x10, SharedFunctionInfo::kStrictModeFunction, &push_receiver);
-    // Do not transform the receiver for native functions.
-    __ Tbnz(x10, SharedFunctionInfo::kNative, &push_receiver);
-
-    // Compute the receiver in sloppy mode.
-    __ JumpIfSmi(receiver, &convert_receiver_to_object);
-    __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_proxy);
-    __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
-                  &use_global_proxy);
-
-    // Check if the receiver is already a JavaScript object.
-    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
-    __ JumpIfObjectType(receiver, x10, x11, FIRST_SPEC_OBJECT_TYPE,
-                        &push_receiver, ge);
-
-    // Call a builtin to convert the receiver to a regular object.
-    __ Bind(&convert_receiver_to_object);
-    __ Mov(x0, receiver);
-    ToObjectStub stub(masm->isolate());
-    __ CallStub(&stub);
-    __ Mov(receiver, x0);
-    __ B(&push_receiver);
-
-    __ Bind(&use_global_proxy);
-    __ Ldr(x10, GlobalObjectMemOperand());
-    __ Ldr(receiver, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset));
-
-    // Push the receiver
-    __ Bind(&push_receiver);
-    __ Push(receiver);
+    __ Push(argc, x1, receiver);
 
     // Copy all arguments from the array to the stack.
 
     // Copy all arguments from the array to the stack.
-    Generate_PushAppliedArguments(
-        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+    Generate_PushAppliedArguments(masm, kArgumentsOffset, kIndexOffset,
+                                  kLimitOffset);
 
 
-    // At the end of the loop, the number of arguments is stored in 'current',
-    // represented as a smi.
+    // At the end of the loop, the number of arguments is stored in x0, untagged
 
 
-    function = x1;  // From now on we want the function to be kept in x1;
-    __ Ldr(function, MemOperand(fp, kFunctionOffset));
-
-    // Call the function.
-    Label call_proxy;
-    ParameterCount actual(x0);
-    __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE, &call_proxy);
-    __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
-    frame_scope.GenerateLeaveFrame();
-    __ Drop(kStackSize);
-    __ Ret();
-
-    // Call the function proxy.
-    __ Bind(&call_proxy);
-    // x0 : argc
-    // x1 : function
-    __ Push(function);  // Add function proxy as last argument.
-    __ Add(x0, x0, 1);
-    __ Mov(x2, 0);
-    __ GetBuiltinFunction(x1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-            RelocInfo::CODE_TARGET);
+    // Call the callable.
+    // TODO(bmeurer): This should be a tail call according to ES6.
+    __ Ldr(x1, MemOperand(fp, kFunctionOffset));
+    __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
   }
   __ Drop(kStackSize);
   __ Ret();
   }
   __ Drop(kStackSize);
   __ Ret();
@@ -1770,6 +1566,140 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
 }
 
 
 }
 
 
+// static
+void Builtins::Generate_CallFunction(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- x0 : the number of arguments (not including the receiver)
+  //  -- x1 : the function to call (checked to be a JSFunction)
+  // -----------------------------------
+
+  Label convert, convert_global_proxy, convert_to_object, done_convert;
+  __ AssertFunction(x1);
+  // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal
+  // slot is "classConstructor".
+  // Enter the context of the function; ToObject has to run in the function
+  // context, and we also need to take the global proxy from the function
+  // context in case of conversion.
+  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
+  __ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
+  __ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
+  // We need to convert the receiver for non-native sloppy mode functions.
+  __ Ldr(w3, FieldMemOperand(x2, SharedFunctionInfo::kCompilerHintsOffset));
+  __ TestAndBranchIfAnySet(w3,
+                           (1 << SharedFunctionInfo::kNative) |
+                               (1 << SharedFunctionInfo::kStrictModeFunction),
+                           &done_convert);
+  {
+    __ Peek(x3, Operand(x0, LSL, kXRegSizeLog2));
+
+    // ----------- S t a t e -------------
+    //  -- x0 : the number of arguments (not including the receiver)
+    //  -- x1 : the function to call (checked to be a JSFunction)
+    //  -- x2 : the shared function info.
+    //  -- x3 : the receiver
+    //  -- cp : the function context.
+    // -----------------------------------
+
+    Label convert_receiver;
+    __ JumpIfSmi(x3, &convert_to_object);
+    STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+    __ CompareObjectType(x3, x4, x4, FIRST_JS_RECEIVER_TYPE);
+    __ B(hs, &done_convert);
+    __ JumpIfRoot(x3, Heap::kUndefinedValueRootIndex, &convert_global_proxy);
+    __ JumpIfNotRoot(x3, Heap::kNullValueRootIndex, &convert_to_object);
+    __ Bind(&convert_global_proxy);
+    {
+      // Patch receiver to global proxy.
+      __ LoadGlobalProxy(x3);
+    }
+    __ B(&convert_receiver);
+    __ Bind(&convert_to_object);
+    {
+      // Convert receiver using ToObject.
+      // TODO(bmeurer): Inline the allocation here to avoid building the frame
+      // in the fast case? (fall back to AllocateInNewSpace?)
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      __ SmiTag(x0);
+      __ Push(x0, x1);
+      __ Mov(x0, x3);
+      ToObjectStub stub(masm->isolate());
+      __ CallStub(&stub);
+      __ Mov(x3, x0);
+      __ Pop(x1, x0);
+      __ SmiUntag(x0);
+    }
+    __ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
+    __ Bind(&convert_receiver);
+    __ Poke(x3, Operand(x0, LSL, kXRegSizeLog2));
+  }
+  __ Bind(&done_convert);
+
+  // ----------- S t a t e -------------
+  //  -- x0 : the number of arguments (not including the receiver)
+  //  -- x1 : the function to call (checked to be a JSFunction)
+  //  -- x2 : the shared function info.
+  //  -- cp : the function context.
+  // -----------------------------------
+
+  __ Ldrsw(
+      x2, FieldMemOperand(x2, SharedFunctionInfo::kFormalParameterCountOffset));
+  __ Ldr(x3, FieldMemOperand(x1, JSFunction::kCodeEntryOffset));
+  ParameterCount actual(x0);
+  ParameterCount expected(x2);
+  __ InvokeCode(x3, expected, actual, JUMP_FUNCTION, NullCallWrapper());
+}
+
+
+// static
+void Builtins::Generate_Call(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- x0 : the number of arguments (not including the receiver)
+  //  -- x1 : the target to call (can be any Object).
+  // -----------------------------------
+
+  Label non_smi, non_jsfunction, non_function;
+  __ JumpIfSmi(x1, &non_function);
+  __ Bind(&non_smi);
+  __ CompareObjectType(x1, x2, x2, JS_FUNCTION_TYPE);
+  __ B(ne, &non_jsfunction);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+  __ Bind(&non_jsfunction);
+  __ Cmp(x2, JS_FUNCTION_PROXY_TYPE);
+  __ B(ne, &non_function);
+
+  // 1. Call to function proxy.
+  // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
+  __ Ldr(x1, FieldMemOperand(x1, JSFunctionProxy::kCallTrapOffset));
+  __ AssertNotSmi(x1);
+  __ B(&non_smi);
+
+  // 2. Call to something else, which might have a [[Call]] internal method (if
+  // not we raise an exception).
+  __ Bind(&non_function);
+  // TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
+  // be awesome instead; i.e. a trivial improvement would be to call into the
+  // runtime and just deal with the API function there instead of returning a
+  // delegate from a runtime call that just jumps back to the runtime once
+  // called. Or, bonus points, call directly into the C API function here, as
+  // we do in some Crankshaft fast cases.
+  // Overwrite the original receiver with the (original) target.
+  __ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
+  {
+    // Determine the delegate for the target (if any).
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    __ SmiTag(x0);
+    __ Push(x0, x1);
+    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
+    __ Mov(x1, x0);
+    __ Pop(x0);
+    __ SmiUntag(x0);
+  }
+  // The delegate is always a regular function.
+  __ AssertFunction(x1);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+}
+
+
 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
   ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline");
   // ----------- S t a t e -------------
 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
   ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline");
   // ----------- S t a t e -------------
index 1720bdfadf3b107bf77b2f4b8028d4dfac497e85..367051d7000ae5c03cbfe75a4a12e59b4ad35cb2 100644 (file)
@@ -2760,33 +2760,9 @@ static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
 }
 
 
 }
 
 
-static void EmitSlowCase(MacroAssembler* masm,
-                         int argc,
-                         Register function,
-                         Register type,
-                         Label* non_function) {
-  // Check for function proxy.
-  // x10 : function type.
-  __ CompareAndBranch(type, JS_FUNCTION_PROXY_TYPE, ne, non_function);
-  __ Push(function);  // put proxy as additional argument
-  __ Mov(x0, argc + 1);
-  __ Mov(x2, 0);
-  __ GetBuiltinFunction(x1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-  {
-    Handle<Code> adaptor =
-        masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
-    __ Jump(adaptor, RelocInfo::CODE_TARGET);
-  }
-
-  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
-  // of the original receiver from the call site).
-  __ Bind(non_function);
-  __ Poke(function, argc * kXRegSize);
-  __ Mov(x0, argc);  // Set up the number of arguments.
-  __ Mov(x2, 0);
-  __ GetBuiltinFunction(function, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET);
+static void EmitSlowCase(MacroAssembler* masm, int argc) {
+  __ Mov(x0, argc);
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -2810,14 +2786,14 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
   // x1  function    the function to call
   Register function = x1;
   Register type = x4;
   // x1  function    the function to call
   Register function = x1;
   Register type = x4;
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
 
   // TODO(jbramley): This function has a lot of unnamed registers. Name them,
   // and tidy things up a bit.
 
   if (needs_checks) {
     // Check that the function is really a JavaScript function.
 
   // TODO(jbramley): This function has a lot of unnamed registers. Name them,
   // and tidy things up a bit.
 
   if (needs_checks) {
     // Check that the function is really a JavaScript function.
-    __ JumpIfSmi(function, &non_function);
+    __ JumpIfSmi(function, &slow);
 
     // Goto slow case if we do not have a function.
     __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow);
 
     // Goto slow case if we do not have a function.
     __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow);
@@ -2852,7 +2828,7 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ Bind(&slow);
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ Bind(&slow);
-    EmitSlowCase(masm, argc, function, type, &non_function);
+    EmitSlowCase(masm, argc);
   }
 
   if (call_as_method) {
   }
 
   if (call_as_method) {
@@ -3002,12 +2978,8 @@ void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
-  CallFunctionNoFeedback(masm,
-                         arg_count(),
-                         true,
-                         CallAsMethod());
-
-  __ Unreachable();
+  __ Mov(x0, arg_count());
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -3022,7 +2994,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
   Label have_js_function;
   int argc = arg_count();
   ParameterCount actual(argc);
   Label have_js_function;
   int argc = arg_count();
   ParameterCount actual(argc);
@@ -3087,7 +3059,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
                     NullCallWrapper());
 
   __ bind(&slow);
                     NullCallWrapper());
 
   __ bind(&slow);
-  EmitSlowCase(masm, argc, function, type, &non_function);
+  EmitSlowCase(masm, argc);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
@@ -3172,7 +3144,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   __ bind(&slow_start);
 
   // Check that the function is really a JavaScript function.
   __ bind(&slow_start);
 
   // Check that the function is really a JavaScript function.
-  __ JumpIfSmi(function, &non_function);
+  __ JumpIfSmi(function, &slow);
 
   // Goto slow case if we do not have a function.
   __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow);
 
   // Goto slow case if we do not have a function.
   __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow);
index 16cdf4a5315a04882cd18c6dfc092386fedb1f4d..75814e83a866396c66b89cb601fa2a02e6bf16d1 100644 (file)
@@ -1613,6 +1613,19 @@ void MacroAssembler::AssertName(Register object) {
 }
 
 
 }
 
 
+void MacroAssembler::AssertFunction(Register object) {
+  if (emit_debug_code()) {
+    AssertNotSmi(object, kOperandIsASmiAndNotAFunction);
+
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireX();
+
+    CompareObjectType(object, temp, temp, JS_FUNCTION_TYPE);
+    Check(eq, kOperandIsNotAFunction);
+  }
+}
+
+
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
                                                      Register scratch) {
   if (emit_debug_code()) {
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
                                                      Register scratch) {
   if (emit_debug_code()) {
@@ -3045,6 +3058,12 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
 }
 
 
 }
 
 
+void MacroAssembler::LoadGlobalProxy(Register dst) {
+  Ldr(dst, GlobalObjectMemOperand());
+  Ldr(dst, FieldMemOperand(dst, GlobalObject::kGlobalProxyOffset));
+}
+
+
 void MacroAssembler::DebugBreak() {
   Mov(x0, 0);
   Mov(x1, ExternalReference(Runtime::kHandleDebuggerStatement, isolate()));
 void MacroAssembler::DebugBreak() {
   Mov(x0, 0);
   Mov(x1, ExternalReference(Runtime::kHandleDebuggerStatement, isolate()));
index a050a74fcbc9311db13a74d2a363426595f21446..29d5c5c5f588ab5fc38322e2b92a92b3f0fa1406 100644 (file)
@@ -959,6 +959,9 @@ class MacroAssembler : public Assembler {
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
+  // Abort execution if argument is not a JSFunction, enabled via --debug-code.
+  void AssertFunction(Register object);
+
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object, Register scratch);
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object, Register scratch);
@@ -1690,6 +1693,9 @@ class MacroAssembler : public Assembler {
 
   void LoadContext(Register dst, int context_chain_length);
 
 
   void LoadContext(Register dst, int context_chain_length);
 
+  // Load the global proxy from the current context.
+  void LoadGlobalProxy(Register dst);
+
   // Emit code for a truncating division by a constant. The dividend register is
   // unchanged. Dividend and result must be different.
   void TruncatingDiv(Register result, Register dividend, int32_t divisor);
   // Emit code for a truncating division by a constant. The dividend register is
   // unchanged. Dividend and result must be different.
   void TruncatingDiv(Register result, Register dividend, int32_t divisor);
index 753989649874ff7e85beb47cbd9f26caef15507a..b63c5fbfba92d25081c9b4c6c2059023144507b1 100644 (file)
@@ -154,10 +154,12 @@ namespace internal {
   V(kObjectFoundInSmiOnlyArray, "Object found in smi-only array")              \
   V(kObjectLiteralWithComplexProperty, "Object literal with complex property") \
   V(kOffsetOutOfRange, "Offset out of range")                                  \
   V(kObjectFoundInSmiOnlyArray, "Object found in smi-only array")              \
   V(kObjectLiteralWithComplexProperty, "Object literal with complex property") \
   V(kOffsetOutOfRange, "Offset out of range")                                  \
+  V(kOperandIsASmiAndNotAFunction, "Operand is a smi and not a function")      \
   V(kOperandIsASmiAndNotAName, "Operand is a smi and not a name")              \
   V(kOperandIsASmiAndNotAString, "Operand is a smi and not a string")          \
   V(kOperandIsASmi, "Operand is a smi")                                        \
   V(kOperandIsNotADate, "Operand is not a date")                               \
   V(kOperandIsASmiAndNotAName, "Operand is a smi and not a name")              \
   V(kOperandIsASmiAndNotAString, "Operand is a smi and not a string")          \
   V(kOperandIsASmi, "Operand is a smi")                                        \
   V(kOperandIsNotADate, "Operand is not a date")                               \
+  V(kOperandIsNotAFunction, "Operand is not a function")                       \
   V(kOperandIsNotAName, "Operand is not a name")                               \
   V(kOperandIsNotANumber, "Operand is not a number")                           \
   V(kOperandIsNotASmi, "Operand is not a smi")                                 \
   V(kOperandIsNotAName, "Operand is not a name")                               \
   V(kOperandIsNotANumber, "Operand is not a number")                           \
   V(kOperandIsNotASmi, "Operand is not a smi")                                 \
index 694273afd99fa99064374f49f4030db1e045f820..58b69d2965c11cd967e18b52bf71d6b4a0acd249 100644 (file)
@@ -70,6 +70,10 @@ enum BuiltinExtraArguments {
 // Define list of builtins implemented in assembly.
 #define BUILTIN_LIST_A(V)                                                    \
   V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState)     \
 // Define list of builtins implemented in assembly.
 #define BUILTIN_LIST_A(V)                                                    \
   V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState)     \
+                                                                             \
+  V(CallFunction, BUILTIN, UNINITIALIZED, kNoExtraICState)                   \
+  V(Call, BUILTIN, UNINITIALIZED, kNoExtraICState)                           \
+                                                                             \
   V(InOptimizationQueue, BUILTIN, UNINITIALIZED, kNoExtraICState)            \
   V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, kNoExtraICState)         \
   V(JSConstructStubForDerived, BUILTIN, UNINITIALIZED, kNoExtraICState)      \
   V(InOptimizationQueue, BUILTIN, UNINITIALIZED, kNoExtraICState)            \
   V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, kNoExtraICState)         \
   V(JSConstructStubForDerived, BUILTIN, UNINITIALIZED, kNoExtraICState)      \
@@ -261,6 +265,11 @@ class Builtins {
   static void Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm);
   static void Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm);
 
   static void Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm);
   static void Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm);
 
+  // ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
+  static void Generate_CallFunction(MacroAssembler* masm);
+  // ES6 section 7.3.12 Call(F, V, [argumentsList])
+  static void Generate_Call(MacroAssembler* masm);
+
   static void Generate_FunctionCall(MacroAssembler* masm);
   static void Generate_FunctionApply(MacroAssembler* masm);
   static void Generate_ReflectApply(MacroAssembler* masm);
   static void Generate_FunctionCall(MacroAssembler* masm);
   static void Generate_FunctionApply(MacroAssembler* masm);
   static void Generate_ReflectApply(MacroAssembler* masm);
index bd7a3593338d0c3ffffcb829c5d760b937cf7444..94edfa4aabd6eb9a859c9a22a3fc3326aa9d323f 100644 (file)
@@ -1953,6 +1953,8 @@ class RegExpConstructResultStub final : public HydrogenCodeStub {
 };
 
 
 };
 
 
+// TODO(bmeurer): Deprecate the CallFunctionStub in favor of the more general
+// Invoke family of builtins.
 class CallFunctionStub: public PlatformCodeStub {
  public:
   CallFunctionStub(Isolate* isolate, int argc, CallFunctionFlags flags)
 class CallFunctionStub: public PlatformCodeStub {
  public:
   CallFunctionStub(Isolate* isolate, int argc, CallFunctionFlags flags)
index 6c23cb7198c0192ef957277620d6a1e53769590e..4685e1636c3a29ee8f00f44809edfd39a7985c5b 100644 (file)
@@ -102,11 +102,8 @@ enum BindingFlags {
   V(BIT_XOR_STRONG_BUILTIN_INDEX, JSFunction, bit_xor_strong_builtin)       \
   V(CALL_FUNCTION_PROXY_AS_CONSTRUCTOR_BUILTIN_INDEX, JSFunction,           \
     call_function_proxy_as_constructor_builtin)                             \
   V(BIT_XOR_STRONG_BUILTIN_INDEX, JSFunction, bit_xor_strong_builtin)       \
   V(CALL_FUNCTION_PROXY_AS_CONSTRUCTOR_BUILTIN_INDEX, JSFunction,           \
     call_function_proxy_as_constructor_builtin)                             \
-  V(CALL_FUNCTION_PROXY_BUILTIN_INDEX, JSFunction,                          \
-    call_function_proxy_builtin)                                            \
   V(CALL_NON_FUNCTION_AS_CONSTRUCTOR_BUILTIN_INDEX, JSFunction,             \
     call_non_function_as_constructor_builtin)                               \
   V(CALL_NON_FUNCTION_AS_CONSTRUCTOR_BUILTIN_INDEX, JSFunction,             \
     call_non_function_as_constructor_builtin)                               \
-  V(CALL_NON_FUNCTION_BUILTIN_INDEX, JSFunction, call_non_function_builtin) \
   V(COMPARE_BUILTIN_INDEX, JSFunction, compare_builtin)                     \
   V(COMPARE_STRONG_BUILTIN_INDEX, JSFunction, compare_strong_builtin)       \
   V(CONCAT_ITERABLE_TO_ARRAY_BUILTIN_INDEX, JSFunction,                     \
   V(COMPARE_BUILTIN_INDEX, JSFunction, compare_builtin)                     \
   V(COMPARE_STRONG_BUILTIN_INDEX, JSFunction, compare_strong_builtin)       \
   V(CONCAT_ITERABLE_TO_ARRAY_BUILTIN_INDEX, JSFunction,                     \
index 2e17fcb00717bab5b6ce5e98fcfac00c3a13cc70..9f64a6005fdcba1887dcfd346b9ac43f378e4f38 100644 (file)
@@ -1587,12 +1587,12 @@ void Assembler::j(Condition cc, byte* entry, RelocInfo::Mode rmode) {
 }
 
 
 }
 
 
-void Assembler::j(Condition cc, Handle<Code> code) {
+void Assembler::j(Condition cc, Handle<Code> code, RelocInfo::Mode rmode) {
   EnsureSpace ensure_space(this);
   // 0000 1111 1000 tttn #32-bit disp
   EMIT(0x0F);
   EMIT(0x80 | cc);
   EnsureSpace ensure_space(this);
   // 0000 1111 1000 tttn #32-bit disp
   EMIT(0x0F);
   EMIT(0x80 | cc);
-  emit(code, RelocInfo::CODE_TARGET);
+  emit(code, rmode);
 }
 
 
 }
 
 
index 3daa294aaec9f1678f9369b898064bd580384075..57987bc7513c6337ae1dff885ddb9fba162f6430 100644 (file)
@@ -856,7 +856,8 @@ class Assembler : public AssemblerBase {
          Label* L,
          Label::Distance distance = Label::kFar);
   void j(Condition cc, byte* entry, RelocInfo::Mode rmode);
          Label* L,
          Label::Distance distance = Label::kFar);
   void j(Condition cc, byte* entry, RelocInfo::Mode rmode);
-  void j(Condition cc, Handle<Code> code);
+  void j(Condition cc, Handle<Code> code,
+         RelocInfo::Mode rmode = RelocInfo::CODE_TARGET);
 
   // Floating-point operations
   void fld(int i);
 
   // Floating-point operations
   void fld(int i);
index 477856cf3f49e7b69cf5af8cdaebd14b8111c450..368b649a69ddde0a2b0e647b07cb9a3674c42970 100644 (file)
@@ -956,161 +956,50 @@ void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
 }
 
 
 }
 
 
+// static
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
-  Factory* factory = masm->isolate()->factory();
-
+  // Stack Layout:
+  // esp[0]           : Return address
+  // esp[8]           : Argument n
+  // esp[16]          : Argument n-1
+  //  ...
+  // esp[8 * n]       : Argument 1
+  // esp[8 * (n + 1)] : Receiver (callable to call)
+  //
+  // eax contains the number of arguments, n, not counting the receiver.
+  //
   // 1. Make sure we have at least one argument.
   // 1. Make sure we have at least one argument.
-  { Label done;
+  {
+    Label done;
     __ test(eax, eax);
     __ test(eax, eax);
-    __ j(not_zero, &done);
-    __ pop(ebx);
-    __ push(Immediate(factory->undefined_value()));
-    __ push(ebx);
+    __ j(not_zero, &done, Label::kNear);
+    __ PopReturnAddressTo(ebx);
+    __ PushRoot(Heap::kUndefinedValueRootIndex);
+    __ PushReturnAddressFrom(ebx);
     __ inc(eax);
     __ bind(&done);
   }
 
     __ inc(eax);
     __ bind(&done);
   }
 
-  // 2. Get the function to call (passed as receiver) from the stack, check
-  //    if it is a function.
-  Label slow, non_function;
-  // 1 ~ return address.
-  __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
-  __ JumpIfSmi(edi, &non_function);
-  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
-  __ j(not_equal, &slow);
-
-
-  // 3a. Patch the first argument if necessary when calling a function.
-  Label shift_arguments;
-  __ Move(edx, Immediate(0));  // indicate regular JS_FUNCTION
-  { Label convert_to_object, use_global_proxy, patch_receiver;
-    // Change context eagerly in case we need the global receiver.
-    __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
-
-    // Do not transform the receiver for strict mode functions.
-    __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
-    __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
-              1 << SharedFunctionInfo::kStrictModeBitWithinByte);
-    __ j(not_equal, &shift_arguments);
-
-    // Do not transform the receiver for natives (shared already in ebx).
-    __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset),
-              1 << SharedFunctionInfo::kNativeBitWithinByte);
-    __ j(not_equal, &shift_arguments);
-
-    // Compute the receiver in sloppy mode.
-    __ mov(ebx, Operand(esp, eax, times_4, 0));  // First argument.
-
-    // Call ToObject on the receiver if it is not an object, or use the
-    // global object if it is null or undefined.
-    __ JumpIfSmi(ebx, &convert_to_object);
-    __ cmp(ebx, factory->null_value());
-    __ j(equal, &use_global_proxy);
-    __ cmp(ebx, factory->undefined_value());
-    __ j(equal, &use_global_proxy);
-    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
-    __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
-    __ j(above_equal, &shift_arguments);
-
-    __ bind(&convert_to_object);
-
-    { // In order to preserve argument count.
-      FrameScope scope(masm, StackFrame::INTERNAL);
-      __ SmiTag(eax);
-      __ push(eax);
-
-      __ mov(eax, ebx);
-      ToObjectStub stub(masm->isolate());
-      __ CallStub(&stub);
-      __ mov(ebx, eax);
-      __ Move(edx, Immediate(0));  // restore
-
-      __ pop(eax);
-      __ SmiUntag(eax);
-    }
-
-    // Restore the function to edi.
-    __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
-    __ jmp(&patch_receiver);
-
-    __ bind(&use_global_proxy);
-    __ mov(ebx,
-           Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
-    __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset));
-
-    __ bind(&patch_receiver);
-    __ mov(Operand(esp, eax, times_4, 0), ebx);
-
-    __ jmp(&shift_arguments);
-  }
-
-  // 3b. Check for function proxy.
-  __ bind(&slow);
-  __ Move(edx, Immediate(1));  // indicate function proxy
-  __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
-  __ j(equal, &shift_arguments);
-  __ bind(&non_function);
-  __ Move(edx, Immediate(2));  // 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.
-  __ mov(Operand(esp, eax, times_4, 0), edi);
+  // 2. Get the callable to call (passed as receiver) from the stack.
+  __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
 
 
-  // 4. Shift arguments and return address one slot down on the stack
+  // 3. 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.
   //    (overwriting the original receiver).  Adjust argument count to make
   //    the original first argument the new receiver.
-  __ bind(&shift_arguments);
-  { Label loop;
+  {
+    Label loop;
     __ mov(ecx, eax);
     __ bind(&loop);
     __ mov(ecx, eax);
     __ bind(&loop);
-    __ mov(ebx, Operand(esp, ecx, times_4, 0));
-    __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
+    __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
+    __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx);
     __ dec(ecx);
     __ j(not_sign, &loop);  // While non-negative (to copy return address).
     __ dec(ecx);
     __ j(not_sign, &loop);  // While non-negative (to copy return address).
-    __ pop(ebx);  // Discard copy of return address.
+    __ pop(ebx);            // Discard copy of return address.
     __ dec(eax);  // One fewer argument (first argument is new receiver).
   }
 
     __ dec(eax);  // One fewer argument (first argument is new receiver).
   }
 
-  // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
-  //     or a function proxy via CALL_FUNCTION_PROXY.
-  { Label function, non_proxy;
-    __ test(edx, edx);
-    __ j(zero, &function);
-    __ Move(ebx, Immediate(0));
-    __ cmp(edx, Immediate(1));
-    __ j(not_equal, &non_proxy);
-
-    __ pop(edx);   // return address
-    __ push(edi);  // re-add proxy object as additional argument
-    __ push(edx);
-    __ inc(eax);
-    __ GetBuiltinEntry(edx, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-           RelocInfo::CODE_TARGET);
-
-    __ bind(&non_proxy);
-    __ GetBuiltinEntry(edx, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-    __ jmp(masm->isolate()->builtins()->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.
-  __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
-  __ mov(ebx,
-         FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
-  __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
-  __ SmiUntag(ebx);
-  __ cmp(eax, ebx);
-  __ j(not_equal,
-       masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
-
-  ParameterCount expected(0);
-  __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper());
+  // 4. Call the callable.
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -1185,7 +1074,7 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
     static const int kReceiverOffset = kArgumentsOffset + kPointerSize;
     static const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
     static const int kReceiverOffset = kArgumentsOffset + kPointerSize;
     static const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
-    __ push(Operand(ebp, kFunctionOffset));  // push this
+    __ push(Operand(ebp, kFunctionOffset));   // push this
     __ push(Operand(ebp, kArgumentsOffset));  // push arguments
     if (targetIsArgument) {
       __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX,
     __ push(Operand(ebp, kArgumentsOffset));  // push arguments
     if (targetIsArgument) {
       __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX,
@@ -1200,87 +1089,18 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
     const int kLimitOffset =
         StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
     const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
     const int kLimitOffset =
         StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
     const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
-    __ push(eax);  // limit
-    __ push(Immediate(0));  // index
-
-    // Get the receiver.
-    __ mov(ebx, Operand(ebp, kReceiverOffset));
-
-    // Check that the function is a JS function (otherwise it must be a proxy).
-    Label push_receiver, use_global_proxy;
-    __ mov(edi, Operand(ebp, kFunctionOffset));
-    __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
-    __ j(not_equal, &push_receiver);
-
-    // Change context eagerly to get the right global object if necessary.
-    __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
-
-    // Compute the receiver.
-    // Do not transform the receiver for strict mode functions.
-    Label call_to_object;
-    __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
-    __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
-              1 << SharedFunctionInfo::kStrictModeBitWithinByte);
-    __ j(not_equal, &push_receiver);
-
-    Factory* factory = masm->isolate()->factory();
-
-    // Do not transform the receiver for natives (shared already in ecx).
-    __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
-              1 << SharedFunctionInfo::kNativeBitWithinByte);
-    __ j(not_equal, &push_receiver);
-
-    // Compute the receiver in sloppy mode.
-    // Call ToObject on the receiver if it is not an object, or use the
-    // global object if it is null or undefined.
-    __ JumpIfSmi(ebx, &call_to_object);
-    __ cmp(ebx, factory->null_value());
-    __ j(equal, &use_global_proxy);
-    __ cmp(ebx, factory->undefined_value());
-    __ j(equal, &use_global_proxy);
-    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
-    __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
-    __ j(above_equal, &push_receiver);
-
-    __ bind(&call_to_object);
-    __ mov(eax, ebx);
-    ToObjectStub stub(masm->isolate());
-    __ CallStub(&stub);
-    __ mov(ebx, eax);
-    __ jmp(&push_receiver);
-
-    __ bind(&use_global_proxy);
-    __ mov(ebx,
-           Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
-    __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset));
-
-    // Push the receiver.
-    __ bind(&push_receiver);
-    __ push(ebx);
+    __ Push(eax);                            // limit
+    __ Push(Immediate(0));                   // index
+    __ Push(Operand(ebp, kReceiverOffset));  // receiver
 
     // Loop over the arguments array, pushing each value to the stack
 
     // Loop over the arguments array, pushing each value to the stack
-    Generate_PushAppliedArguments(
-        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+    Generate_PushAppliedArguments(masm, kArgumentsOffset, kIndexOffset,
+                                  kLimitOffset);
 
 
-    // Call the function.
-    Label call_proxy;
-    ParameterCount actual(eax);
+    // Call the callable.
+    // TODO(bmeurer): This should be a tail call according to ES6.
     __ mov(edi, Operand(ebp, kFunctionOffset));
     __ mov(edi, Operand(ebp, kFunctionOffset));
-    __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
-    __ j(not_equal, &call_proxy);
-    __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper());
-
-    frame_scope.GenerateLeaveFrame();
-    __ ret(kStackSize * kPointerSize);  // remove this, receiver, and arguments
-
-    // Call the function proxy.
-    __ bind(&call_proxy);
-    __ push(edi);  // add function proxy as last argument
-    __ inc(eax);
-    __ Move(ebx, Immediate(0));
-    __ GetBuiltinEntry(edx, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-            RelocInfo::CODE_TARGET);
+    __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 
     // Leave internal frame.
   }
 
     // Leave internal frame.
   }
@@ -1617,6 +1437,146 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
 }
 
 
 }
 
 
+// static
+void Builtins::Generate_CallFunction(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax : the number of arguments (not including the receiver)
+  //  -- edi : the function to call (checked to be a JSFunction)
+  // -----------------------------------
+
+  Label convert, convert_global_proxy, convert_to_object, done_convert;
+  __ AssertFunction(edi);
+  // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal
+  // slot is "classConstructor".
+  // Enter the context of the function; ToObject has to run in the function
+  // context, and we also need to take the global proxy from the function
+  // context in case of conversion.
+  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
+  STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
+                SharedFunctionInfo::kStrictModeByteOffset);
+  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
+  __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+  // We need to convert the receiver for non-native sloppy mode functions.
+  __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
+            (1 << SharedFunctionInfo::kNativeBitWithinByte) |
+                (1 << SharedFunctionInfo::kStrictModeBitWithinByte));
+  __ j(not_zero, &done_convert);
+  {
+    __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
+
+    // ----------- S t a t e -------------
+    //  -- eax : the number of arguments (not including the receiver)
+    //  -- ecx : the receiver
+    //  -- edx : the shared function info.
+    //  -- edi : the function to call (checked to be a JSFunction)
+    //  -- esi : the function context.
+    // -----------------------------------
+
+    Label convert_receiver;
+    __ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
+    STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+    __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
+    __ j(above_equal, &done_convert);
+    __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex, &convert_global_proxy,
+                  Label::kNear);
+    __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object,
+                     Label::kNear);
+    __ bind(&convert_global_proxy);
+    {
+      // Patch receiver to global proxy.
+      __ LoadGlobalProxy(ecx);
+    }
+    __ jmp(&convert_receiver);
+    __ bind(&convert_to_object);
+    {
+      // Convert receiver using ToObject.
+      // TODO(bmeurer): Inline the allocation here to avoid building the frame
+      // in the fast case? (fall back to AllocateInNewSpace?)
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      __ SmiTag(eax);
+      __ Push(eax);
+      __ Push(edi);
+      __ mov(eax, ecx);
+      ToObjectStub stub(masm->isolate());
+      __ CallStub(&stub);
+      __ mov(ecx, eax);
+      __ Pop(edi);
+      __ Pop(eax);
+      __ SmiUntag(eax);
+    }
+    __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+    __ bind(&convert_receiver);
+    __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx);
+  }
+  __ bind(&done_convert);
+
+  // ----------- S t a t e -------------
+  //  -- eax : the number of arguments (not including the receiver)
+  //  -- edx : the shared function info.
+  //  -- edi : the function to call (checked to be a JSFunction)
+  //  -- esi : the function context.
+  // -----------------------------------
+
+  __ mov(ebx,
+         FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
+  __ SmiUntag(ebx);
+  ParameterCount actual(eax);
+  ParameterCount expected(ebx);
+  __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), expected,
+                actual, JUMP_FUNCTION, NullCallWrapper());
+}
+
+
+// static
+void Builtins::Generate_Call(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax : the number of arguments (not including the receiver)
+  //  -- edi : the target to call (can be any Object).
+  // -----------------------------------
+
+  Label non_smi, non_function;
+  __ JumpIfSmi(edi, &non_function);
+  __ bind(&non_smi);
+  __ CmpObjectType(edi, JS_FUNCTION_TYPE, edx);
+  __ j(equal, masm->isolate()->builtins()->CallFunction(),
+       RelocInfo::CODE_TARGET);
+  __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
+  __ j(not_equal, &non_function);
+
+  // 1. Call to function proxy.
+  // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
+  __ mov(edi, FieldOperand(edi, JSFunctionProxy::kCallTrapOffset));
+  __ AssertNotSmi(edi);
+  __ jmp(&non_smi);
+
+  // 2. Call to something else, which might have a [[Call]] internal method (if
+  // not we raise an exception).
+  __ bind(&non_function);
+  // TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
+  // be awesome instead; i.e. a trivial improvement would be to call into the
+  // runtime and just deal with the API function there instead of returning a
+  // delegate from a runtime call that just jumps back to the runtime once
+  // called. Or, bonus points, call directly into the C API function here, as
+  // we do in some Crankshaft fast cases.
+  // Overwrite the original receiver with the (original) target.
+  __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
+  {
+    // Determine the delegate for the target (if any).
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    __ SmiTag(eax);
+    __ Push(eax);
+    __ Push(edi);
+    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
+    __ mov(edi, eax);
+    __ Pop(eax);
+    __ SmiUntag(eax);
+  }
+  // The delegate is always a regular function.
+  __ AssertFunction(edi);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+}
+
+
 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- eax : actual number of arguments
 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- eax : actual number of arguments
index e32b1155ae70589e6f8cad5b354e663d4d71f8da..029e8cf2367854ff5b93e51a947a4840e24861c6 100644 (file)
@@ -2039,33 +2039,9 @@ static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
 }
 
 
 }
 
 
-static void EmitSlowCase(Isolate* isolate,
-                         MacroAssembler* masm,
-                         int argc,
-                         Label* non_function) {
-  // Check for function proxy.
-  __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
-  __ j(not_equal, non_function);
-  __ pop(ecx);
-  __ push(edi);  // put proxy as additional argument under return address
-  __ push(ecx);
-  __ Move(eax, Immediate(argc + 1));
-  __ Move(ebx, Immediate(0));
-  __ GetBuiltinEntry(edx, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-  {
-    Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
-    __ jmp(adaptor, RelocInfo::CODE_TARGET);
-  }
-
-  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
-  // of the original receiver from the call site).
-  __ bind(non_function);
-  __ mov(Operand(esp, (argc + 1) * kPointerSize), edi);
-  __ Move(eax, Immediate(argc));
-  __ Move(ebx, Immediate(0));
-  __ GetBuiltinEntry(edx, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-  Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
-  __ jmp(adaptor, RelocInfo::CODE_TARGET);
+static void EmitSlowCase(Isolate* isolate, MacroAssembler* masm, int argc) {
+  __ Set(eax, argc);
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -2086,11 +2062,11 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
                                    int argc, bool needs_checks,
                                    bool call_as_method) {
   // edi : the function to call
                                    int argc, bool needs_checks,
                                    bool call_as_method) {
   // edi : the function to call
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
 
   if (needs_checks) {
     // Check that the function really is a JavaScript function.
 
   if (needs_checks) {
     // Check that the function really is a JavaScript function.
-    __ JumpIfSmi(edi, &non_function);
+    __ JumpIfSmi(edi, &slow);
 
     // Goto slow case if we do not have a function.
     __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
 
     // Goto slow case if we do not have a function.
     __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
@@ -2125,8 +2101,7 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ bind(&slow);
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ bind(&slow);
-    // (non_function is bound in EmitSlowCase)
-    EmitSlowCase(masm->isolate(), masm, argc, &non_function);
+    EmitSlowCase(masm->isolate(), masm, argc);
   }
 
   if (call_as_method) {
   }
 
   if (call_as_method) {
@@ -2270,13 +2245,8 @@ void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
-  CallFunctionNoFeedback(masm,
-                         arg_count(),
-                         true,
-                         CallAsMethod());
-
-  // Unreachable.
-  __ int3();
+  __ Set(eax, arg_count());
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -2290,7 +2260,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
   Label have_js_function;
   int argc = arg_count();
   ParameterCount actual(argc);
   Label have_js_function;
   int argc = arg_count();
   ParameterCount actual(argc);
@@ -2343,7 +2313,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper());
 
   __ bind(&slow);
   __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper());
 
   __ bind(&slow);
-  EmitSlowCase(isolate, masm, argc, &non_function);
+  EmitSlowCase(isolate, masm, argc);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
@@ -2424,7 +2394,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   __ bind(&slow_start);
 
   // Check that the function really is a JavaScript function.
   __ bind(&slow_start);
 
   // Check that the function really is a JavaScript function.
-  __ JumpIfSmi(edi, &non_function);
+  __ JumpIfSmi(edi, &slow);
 
   // Goto slow case if we do not have a function.
   __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
 
   // Goto slow case if we do not have a function.
   __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
index b05384d05257068bead0af1cc966fe4bd77cb379..96c81609be937fb1fda59a51dbccb9ec837e5a38 100644 (file)
@@ -116,6 +116,12 @@ void MacroAssembler::CompareRoot(const Operand& with,
 }
 
 
 }
 
 
+void MacroAssembler::PushRoot(Heap::RootListIndex index) {
+  DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
+  Push(isolate()->heap()->root_handle(index));
+}
+
+
 void MacroAssembler::InNewSpace(
     Register object,
     Register scratch,
 void MacroAssembler::InNewSpace(
     Register object,
     Register scratch,
@@ -804,6 +810,18 @@ void MacroAssembler::AssertName(Register object) {
 }
 
 
 }
 
 
+void MacroAssembler::AssertFunction(Register object) {
+  if (emit_debug_code()) {
+    test(object, Immediate(kSmiTagMask));
+    Check(not_equal, kOperandIsASmiAndNotAFunction);
+    Push(object);
+    CmpObjectType(object, JS_FUNCTION_TYPE, object);
+    Pop(object);
+    Check(equal, kOperandIsNotAFunction);
+  }
+}
+
+
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
   if (emit_debug_code()) {
     Label done_checking;
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
   if (emit_debug_code()) {
     Label done_checking;
@@ -2097,6 +2115,12 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
 }
 
 
 }
 
 
+void MacroAssembler::LoadGlobalProxy(Register dst) {
+  mov(dst, GlobalObjectOperand());
+  mov(dst, FieldOperand(dst, GlobalObject::kGlobalProxyOffset));
+}
+
+
 void MacroAssembler::LoadTransitionedArrayMapConditional(
     ElementsKind expected_kind,
     ElementsKind transitioned_kind,
 void MacroAssembler::LoadTransitionedArrayMapConditional(
     ElementsKind expected_kind,
     ElementsKind transitioned_kind,
index dd90650f6d588d63fa260a7f8bfd43399f64b63c..f57bdb7e866eb62bb23d76216f02e7c8b6b3ad21 100644 (file)
@@ -71,6 +71,16 @@ class MacroAssembler: public Assembler {
   void Load(Register dst, const Operand& src, Representation r);
   void Store(Register src, const Operand& dst, Representation r);
 
   void Load(Register dst, const Operand& src, Representation r);
   void Store(Register src, const Operand& dst, Representation r);
 
+  // Load a register with a long value as efficiently as possible.
+  void Set(Register dst, int32_t x) {
+    if (x == 0) {
+      xor_(dst, dst);
+    } else {
+      mov(dst, Immediate(x));
+    }
+  }
+  void Set(const Operand& dst, int32_t x) { mov(dst, Immediate(x)); }
+
   // Operations on roots in the root-array.
   void LoadRoot(Register destination, Heap::RootListIndex index);
   void StoreRoot(Register source, Register scratch, Heap::RootListIndex index);
   // Operations on roots in the root-array.
   void LoadRoot(Register destination, Heap::RootListIndex index);
   void StoreRoot(Register source, Register scratch, Heap::RootListIndex index);
@@ -79,6 +89,22 @@ class MacroAssembler: public Assembler {
   // and not in new space).
   void CompareRoot(Register with, Heap::RootListIndex index);
   void CompareRoot(const Operand& with, Heap::RootListIndex index);
   // and not in new space).
   void CompareRoot(Register with, Heap::RootListIndex index);
   void CompareRoot(const Operand& with, Heap::RootListIndex index);
+  void PushRoot(Heap::RootListIndex index);
+
+  // Compare the object in a register to a value and jump if they are equal.
+  void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal,
+                  Label::Distance if_equal_distance = Label::kNear) {
+    CompareRoot(with, index);
+    j(equal, if_equal, if_equal_distance);
+  }
+
+  // Compare the object in a register to a value and jump if they are not equal.
+  void JumpIfNotRoot(Register with, Heap::RootListIndex index,
+                     Label* if_not_equal,
+                     Label::Distance if_not_equal_distance = Label::kNear) {
+    CompareRoot(with, index);
+    j(not_equal, if_not_equal, if_not_equal_distance);
+  }
 
   // ---------------------------------------------------------------------------
   // GC Support
 
   // ---------------------------------------------------------------------------
   // GC Support
@@ -262,6 +288,9 @@ class MacroAssembler: public Assembler {
   // Find the function context up the context chain.
   void LoadContext(Register dst, int context_chain_length);
 
   // Find the function context up the context chain.
   void LoadContext(Register dst, int context_chain_length);
 
+  // Load the global proxy from the current context.
+  void LoadGlobalProxy(Register dst);
+
   // Conditionally load the cached Array transitioned map of type
   // transitioned_kind from the native context if the map in register
   // map_in_out is the cached Array map in the native context of
   // Conditionally load the cached Array transitioned map of type
   // transitioned_kind from the native context if the map in register
   // map_in_out is the cached Array map in the native context of
@@ -565,6 +594,9 @@ class MacroAssembler: public Assembler {
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
+  // Abort execution if argument is not a JSFunction, enabled via --debug-code.
+  void AssertFunction(Register object);
+
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object);
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object);
@@ -803,8 +835,14 @@ class MacroAssembler: public Assembler {
   void Drop(int element_count);
 
   void Call(Label* target) { call(target); }
   void Drop(int element_count);
 
   void Call(Label* target) { call(target); }
+  void Call(Handle<Code> target, RelocInfo::Mode rmode) { call(target, rmode); }
+  void Jump(Handle<Code> target, RelocInfo::Mode rmode) { jmp(target, rmode); }
   void Push(Register src) { push(src); }
   void Push(Register src) { push(src); }
+  void Push(const Operand& src) { push(src); }
+  void Push(Immediate value) { push(value); }
   void Pop(Register dst) { pop(dst); }
   void Pop(Register dst) { pop(dst); }
+  void PushReturnAddressFrom(Register src) { push(src); }
+  void PopReturnAddressTo(Register dst) { pop(dst); }
 
   // Non-SSE2 instructions.
   void Pextrd(Register dst, XMMRegister src, int8_t imm8);
 
   // Non-SSE2 instructions.
   void Pextrd(Register dst, XMMRegister src, int8_t imm8);
index bd8c85285af4574d7d72e5e25c2cef13161a6564..6e51b0764e9c5dc0fcbebdb125a5c2782905be40 100644 (file)
@@ -1252,129 +1252,31 @@ void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
 }
 
 
 }
 
 
+// static
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
   // 1. Make sure we have at least one argument.
   // a0: actual number of arguments
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
   // 1. Make sure we have at least one argument.
   // a0: actual number of arguments
-  { Label done;
+  {
+    Label done;
     __ Branch(&done, ne, a0, Operand(zero_reg));
     __ Branch(&done, ne, a0, Operand(zero_reg));
-    __ LoadRoot(t2, Heap::kUndefinedValueRootIndex);
-    __ push(t2);
+    __ PushRoot(Heap::kUndefinedValueRootIndex);
     __ Addu(a0, a0, Operand(1));
     __ bind(&done);
   }
 
     __ Addu(a0, a0, Operand(1));
     __ bind(&done);
   }
 
-  // 2. Get the function to call (passed as receiver) from the stack, check
-  //    if it is a function.
+  // 2. Get the function to call (passed as receiver) from the stack.
   // a0: actual number of arguments
   // a0: actual number of arguments
-  Label slow, non_function;
   __ sll(at, a0, kPointerSizeLog2);
   __ addu(at, sp, at);
   __ lw(a1, MemOperand(at));
   __ sll(at, a0, kPointerSizeLog2);
   __ addu(at, sp, at);
   __ lw(a1, MemOperand(at));
-  __ JumpIfSmi(a1, &non_function);
-  __ GetObjectType(a1, a2, a2);
-  __ 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::NONE32));  // Indicate regular JS_FUNCTION.
-  { Label convert_to_object, use_global_proxy, patch_receiver;
-    // Change context eagerly in case we need the global receiver.
-    __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
-
-    // Do not transform the receiver for strict mode functions.
-    __ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
-    __ lw(a3, FieldMemOperand(a2, SharedFunctionInfo::kCompilerHintsOffset));
-    __ And(t3, a3, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
-                                 kSmiTagSize)));
-    __ Branch(&shift_arguments, ne, t3, Operand(zero_reg));
-
-    // Do not transform the receiver for native (Compilerhints already in a3).
-    __ And(t3, a3, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
-    __ Branch(&shift_arguments, ne, t3, Operand(zero_reg));
-
-    // Compute the receiver in sloppy mode.
-    // Load first argument in a2. a2 = -kPointerSize(sp + n_args << 2).
-    __ sll(at, a0, kPointerSizeLog2);
-    __ addu(a2, sp, at);
-    __ lw(a2, MemOperand(a2, -kPointerSize));
-    // a0: actual number of arguments
-    // a1: function
-    // a2: first argument
-    __ JumpIfSmi(a2, &convert_to_object, t2);
-
-    __ LoadRoot(a3, Heap::kUndefinedValueRootIndex);
-    __ Branch(&use_global_proxy, eq, a2, Operand(a3));
-    __ LoadRoot(a3, Heap::kNullValueRootIndex);
-    __ Branch(&use_global_proxy, eq, a2, Operand(a3));
 
 
-    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
-    __ GetObjectType(a2, a3, a3);
-    __ Branch(&shift_arguments, ge, a3, Operand(FIRST_SPEC_OBJECT_TYPE));
-
-    __ bind(&convert_to_object);
-    // Enter an internal frame in order to preserve argument count.
-    {
-      FrameScope scope(masm, StackFrame::INTERNAL);
-      __ sll(a0, a0, kSmiTagSize);  // Smi tagged.
-      __ push(a0);
-      __ mov(a0, a2);
-      ToObjectStub stub(masm->isolate());
-      __ CallStub(&stub);
-      __ 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));
-    __ Branch(USE_DELAY_SLOT, &patch_receiver);
-    __ li(t0, Operand(0, RelocInfo::NONE32));  // In delay slot.
-
-    __ bind(&use_global_proxy);
-    __ lw(a2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
-    __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalProxyOffset));
-
-    __ bind(&patch_receiver);
-    __ sll(at, a0, kPointerSizeLog2);
-    __ addu(a3, sp, at);
-    __ sw(a2, MemOperand(a3, -kPointerSize));
-
-    __ Branch(&shift_arguments);
-  }
-
-  // 3b. Check for function proxy.
-  __ bind(&slow);
-  __ li(t0, Operand(1, RelocInfo::NONE32));  // Indicate function proxy.
-  __ Branch(&shift_arguments, eq, a2, Operand(JS_FUNCTION_PROXY_TYPE));
-
-  __ bind(&non_function);
-  __ li(t0, Operand(2, RelocInfo::NONE32));  // 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
-  // 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));
-
-  // 4. Shift arguments and return address one slot down on the stack
+  // 3. 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
   //    (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;
+  {
+    Label loop;
     // Calculate the copy start address (destination). Copy end address is sp.
     __ sll(at, a0, kPointerSizeLog2);
     __ addu(a2, sp, at);
     // Calculate the copy start address (destination). Copy end address is sp.
     __ sll(at, a0, kPointerSizeLog2);
     __ addu(a2, sp, at);
@@ -1390,46 +1292,8 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
     __ Pop();
   }
 
     __ Pop();
   }
 
-  // 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
-  // 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);
-    __ Branch(&non_proxy, ne, t0, Operand(1));
-
-    __ push(a1);  // Re-add proxy object as additional argument.
-    __ Addu(a0, a0, Operand(1));
-    __ GetBuiltinFunction(a1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-            RelocInfo::CODE_TARGET);
-
-    __ bind(&non_proxy);
-    __ GetBuiltinFunction(a1, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-    __ Jump(masm->isolate()->builtins()->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.
-  // a0: actual number of arguments
-  // a1: function
-  __ lw(a3, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
-  __ lw(a2,
-         FieldMemOperand(a3, SharedFunctionInfo::kFormalParameterCountOffset));
-  __ sra(a2, a2, kSmiTagSize);
-  // Check formal and actual parameter counts.
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET, ne, a2, Operand(a0));
-
-  __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
-  ParameterCount expected(0);
-  __ InvokeCode(a3, expected, expected, JUMP_FUNCTION, NullCallWrapper());
+  // 4. Call the callable.
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -1493,9 +1357,8 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
     const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
     __ lw(a0, MemOperand(fp, kFunctionOffset));  // Get the function.
     const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
     __ lw(a0, MemOperand(fp, kFunctionOffset));  // Get the function.
-    __ push(a0);
-    __ lw(a0, MemOperand(fp, kArgumentsOffset));  // Get the args array.
-    __ push(a0);
+    __ lw(a1, MemOperand(fp, kArgumentsOffset));  // Get the args array.
+    __ Push(a0, a1);
     // Returns (in v0) number of arguments to copy to stack as Smi.
     if (targetIsArgument) {
       __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX,
     // Returns (in v0) number of arguments to copy to stack as Smi.
     if (targetIsArgument) {
       __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX,
@@ -1513,89 +1376,18 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
     const int kLimitOffset =
         StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
     __ mov(a1, zero_reg);
     const int kLimitOffset =
         StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
     __ mov(a1, zero_reg);
-    __ Push(v0, a1);  // Limit and initial index.
-
-    // Get the receiver.
-    __ lw(a0, MemOperand(fp, kReceiverOffset));
-
-    // 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));
-
-    // 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));
-
-    // Compute the receiver.
-    // Do not transform the receiver for strict mode functions.
-    Label call_to_object, use_global_proxy;
-    __ 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 sloppy mode.
-    __ JumpIfSmi(a0, &call_to_object);
-    __ LoadRoot(a1, Heap::kNullValueRootIndex);
-    __ Branch(&use_global_proxy, eq, a0, Operand(a1));
-    __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
-    __ Branch(&use_global_proxy, 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);
-    ToObjectStub stub(masm->isolate());
-    __ CallStub(&stub);
-    __ mov(a0, v0);  // Put object in a0 to match other paths to push_receiver.
-    __ Branch(&push_receiver);
-
-    __ bind(&use_global_proxy);
-    __ lw(a0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
-    __ lw(a0, FieldMemOperand(a0, GlobalObject::kGlobalProxyOffset));
-
-    // Push the receiver.
-    // a0: receiver
-    __ bind(&push_receiver);
-    __ push(a0);
+    __ lw(a2, MemOperand(fp, kReceiverOffset));
+    __ Push(v0, a1, a2);  // limit, initial index and receiver.
 
     // Copy all arguments from the array to the stack.
 
     // Copy all arguments from the array to the stack.
-    Generate_PushAppliedArguments(
-        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+    Generate_PushAppliedArguments(masm, kArgumentsOffset, kIndexOffset,
+                                  kLimitOffset);
 
 
-    // Call the function.
-    Label call_proxy;
-    ParameterCount actual(a0);
+    // Call the callable.
+    // TODO(bmeurer): This should be a tail call according to ES6.
     __ lw(a1, MemOperand(fp, kFunctionOffset));
     __ lw(a1, MemOperand(fp, kFunctionOffset));
-    __ GetObjectType(a1, a2, a2);
-    __ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE));
-
-    __ InvokeFunction(a1, actual, CALL_FUNCTION, NullCallWrapper());
-
-    frame_scope.GenerateLeaveFrame();
-    __ Ret(USE_DELAY_SLOT);
-    __ Addu(sp, sp, Operand(kStackSize * kPointerSize));  // In delay slot.
+    __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 
 
-    // Call the function proxy.
-    __ bind(&call_proxy);
-    __ push(a1);  // Add function proxy as last argument.
-    __ Addu(a0, a0, Operand(1));
-    __ li(a2, Operand(0, RelocInfo::NONE32));
-    __ GetBuiltinFunction(a1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-            RelocInfo::CODE_TARGET);
     // Tear down the internal frame and remove function, receiver and args.
   }
 
     // Tear down the internal frame and remove function, receiver and args.
   }
 
@@ -1731,6 +1523,147 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
 }
 
 
 }
 
 
+// static
+void Builtins::Generate_CallFunction(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- a0 : the number of arguments (not including the receiver)
+  //  -- a1 : the function to call (checked to be a JSFunction)
+  // -----------------------------------
+
+  Label convert, convert_global_proxy, convert_to_object, done_convert;
+  __ AssertFunction(a1);
+  // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal
+  // slot is "classConstructor".
+  // Enter the context of the function; ToObject has to run in the function
+  // context, and we also need to take the global proxy from the function
+  // context in case of conversion.
+  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
+  STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
+                SharedFunctionInfo::kStrictModeByteOffset);
+  __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
+  __ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+  // We need to convert the receiver for non-native sloppy mode functions.
+  __ lbu(a3, FieldMemOperand(a2, SharedFunctionInfo::kNativeByteOffset));
+  __ And(at, a3, Operand((1 << SharedFunctionInfo::kNativeBitWithinByte) |
+                         (1 << SharedFunctionInfo::kStrictModeBitWithinByte)));
+  __ Branch(&done_convert, ne, at, Operand(zero_reg));
+  {
+    __ sll(at, a0, kPointerSizeLog2);
+    __ addu(at, sp, at);
+    __ lw(a3, MemOperand(at));
+
+    // ----------- S t a t e -------------
+    //  -- a0 : the number of arguments (not including the receiver)
+    //  -- a1 : the function to call (checked to be a JSFunction)
+    //  -- a2 : the shared function info.
+    //  -- a3 : the receiver
+    //  -- cp : the function context.
+    // -----------------------------------
+
+    Label convert_receiver;
+    __ JumpIfSmi(a3, &convert_to_object);
+    STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+    __ GetObjectType(a3, t0, t0);
+    __ Branch(&done_convert, hs, t0, Operand(FIRST_JS_RECEIVER_TYPE));
+    __ JumpIfRoot(a3, Heap::kUndefinedValueRootIndex, &convert_global_proxy);
+    __ JumpIfNotRoot(a3, Heap::kNullValueRootIndex, &convert_to_object);
+    __ bind(&convert_global_proxy);
+    {
+      // Patch receiver to global proxy.
+      __ LoadGlobalProxy(a3);
+    }
+    __ Branch(&convert_receiver);
+    __ bind(&convert_to_object);
+    {
+      // Convert receiver using ToObject.
+      // TODO(bmeurer): Inline the allocation here to avoid building the frame
+      // in the fast case? (fall back to AllocateInNewSpace?)
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      __ sll(a0, a0, kSmiTagSize);  // Smi tagged.
+      __ Push(a0, a1);
+      __ mov(a0, a3);
+      ToObjectStub stub(masm->isolate());
+      __ CallStub(&stub);
+      __ mov(a3, v0);
+      __ Pop(a0, a1);
+      __ sra(a0, a0, kSmiTagSize);  // Un-tag.
+    }
+    __ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+    __ bind(&convert_receiver);
+    __ sll(at, a0, kPointerSizeLog2);
+    __ addu(at, sp, at);
+    __ sw(a3, MemOperand(at));
+  }
+  __ bind(&done_convert);
+
+  // ----------- S t a t e -------------
+  //  -- a0 : the number of arguments (not including the receiver)
+  //  -- a1 : the function to call (checked to be a JSFunction)
+  //  -- a2 : the shared function info.
+  //  -- cp : the function context.
+  // -----------------------------------
+
+  __ lw(a2,
+        FieldMemOperand(a2, SharedFunctionInfo::kFormalParameterCountOffset));
+  __ sra(a2, a2, kSmiTagSize);  // Un-tag.
+  __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
+  ParameterCount actual(a0);
+  ParameterCount expected(a2);
+  __ InvokeCode(a3, expected, actual, JUMP_FUNCTION, NullCallWrapper());
+}
+
+
+// static
+void Builtins::Generate_Call(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- a0 : the number of arguments (not including the receiver)
+  //  -- a1 : the target to call (can be any Object).
+  // -----------------------------------
+
+  Label non_smi, non_function;
+  __ JumpIfSmi(a1, &non_function);
+  __ bind(&non_smi);
+  __ GetObjectType(a1, a2, a2);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
+          eq, a2, Operand(JS_FUNCTION_TYPE));
+  __ Branch(&non_function, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE));
+
+
+  // 1. Call to function proxy.
+  // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
+  __ lw(a1, FieldMemOperand(a1, JSFunctionProxy::kCallTrapOffset));
+  __ AssertNotSmi(a1);
+  __ Branch(&non_smi);
+
+  // 2. Call to something else, which might have a [[Call]] internal method (if
+  // not we raise an exception).
+  __ bind(&non_function);
+  // TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
+  // be awesome instead; i.e. a trivial improvement would be to call into the
+  // runtime and just deal with the API function there instead of returning a
+  // delegate from a runtime call that just jumps back to the runtime once
+  // called. Or, bonus points, call directly into the C API function here, as
+  // we do in some Crankshaft fast cases.
+  // Overwrite the original receiver with the (original) target.
+  __ sll(at, a0, kPointerSizeLog2);
+  __ addu(at, sp, at);
+  __ sw(a1, MemOperand(at));
+  {
+    // Determine the delegate for the target (if any).
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    __ sll(a0, a0, kSmiTagSize);  // Smi tagged.
+    __ Push(a0, a1);
+    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
+    __ mov(a1, v0);
+    __ Pop(a0);
+    __ sra(a0, a0, kSmiTagSize);  // Un-tag.
+  }
+  // The delegate is always a regular function.
+  __ AssertFunction(a1);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+}
+
+
 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
   // State setup as expected by MacroAssembler::InvokePrologue.
   // ----------- S t a t e -------------
 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
   // State setup as expected by MacroAssembler::InvokePrologue.
   // ----------- S t a t e -------------
index 11b14be6671a47c84e0356a20bf4722407d10fd6..3053cb769f0c1046142f1421b3ec15c91039a111 100644 (file)
@@ -2524,30 +2524,9 @@ static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
 }
 
 
 }
 
 
-static void EmitSlowCase(MacroAssembler* masm,
-                         int argc,
-                         Label* non_function) {
-  // Check for function proxy.
-  __ Branch(non_function, ne, t0, Operand(JS_FUNCTION_PROXY_TYPE));
-  __ push(a1);  // put proxy as additional argument
-  __ li(a0, Operand(argc + 1, RelocInfo::NONE32));
-  __ mov(a2, zero_reg);
-  __ GetBuiltinFunction(a1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-  {
-    Handle<Code> adaptor =
-        masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
-    __ Jump(adaptor, RelocInfo::CODE_TARGET);
-  }
-
-  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
-  // of the original receiver from the call site).
-  __ bind(non_function);
-  __ sw(a1, MemOperand(sp, argc * kPointerSize));
-  __ li(a0, Operand(argc));  // Set up the number of arguments.
-  __ mov(a2, zero_reg);
-  __ GetBuiltinFunction(a1, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET);
+static void EmitSlowCase(MacroAssembler* masm, int argc) {
+  __ li(a0, Operand(argc));
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -2569,12 +2548,12 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
                                    int argc, bool needs_checks,
                                    bool call_as_method) {
   // a1 : the function to call
                                    int argc, bool needs_checks,
                                    bool call_as_method) {
   // a1 : the function to call
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
 
   if (needs_checks) {
     // Check that the function is really a JavaScript function.
     // a1: pushed function (to be verified)
 
   if (needs_checks) {
     // Check that the function is really a JavaScript function.
     // a1: pushed function (to be verified)
-    __ JumpIfSmi(a1, &non_function);
+    __ JumpIfSmi(a1, &slow);
 
     // Goto slow case if we do not have a function.
     __ GetObjectType(a1, t0, t0);
 
     // Goto slow case if we do not have a function.
     __ GetObjectType(a1, t0, t0);
@@ -2609,7 +2588,7 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ bind(&slow);
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ bind(&slow);
-    EmitSlowCase(masm, argc, &non_function);
+    EmitSlowCase(masm, argc);
   }
 
   if (call_as_method) {
   }
 
   if (call_as_method) {
@@ -2743,13 +2722,8 @@ void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
-  CallFunctionNoFeedback(masm,
-                         arg_count(),
-                         true,
-                         CallAsMethod());
-
-  // Unreachable.
-  __ stop("Unexpected code address");
+  __ li(a0, Operand(arg_count()));
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -2762,7 +2736,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
   Label have_js_function;
   int argc = arg_count();
   ParameterCount actual(argc);
   Label have_js_function;
   int argc = arg_count();
   ParameterCount actual(argc);
@@ -2816,7 +2790,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   __ InvokeFunction(a1, actual, JUMP_FUNCTION, NullCallWrapper());
 
   __ bind(&slow);
   __ InvokeFunction(a1, actual, JUMP_FUNCTION, NullCallWrapper());
 
   __ bind(&slow);
-  EmitSlowCase(masm, argc, &non_function);
+  EmitSlowCase(masm, argc);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
@@ -2904,7 +2878,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   __ bind(&slow_start);
   // Check that the function is really a JavaScript function.
   // r1: pushed function (to be verified)
   __ bind(&slow_start);
   // Check that the function is really a JavaScript function.
   // r1: pushed function (to be verified)
-  __ JumpIfSmi(a1, &non_function);
+  __ JumpIfSmi(a1, &slow);
 
   // Goto slow case if we do not have a function.
   __ GetObjectType(a1, t0, t0);
 
   // Goto slow case if we do not have a function.
   __ GetObjectType(a1, t0, t0);
index 9ba814ae2ff85887350cd57c7d0cbe739834f1a1..cad08049f2ab17218e444c576f265ab03e07ad0a 100644 (file)
@@ -1,3 +1,4 @@
+
 // Copyright 2012 the V8 project authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 // Copyright 2012 the V8 project authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
@@ -4743,6 +4744,12 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
 }
 
 
 }
 
 
+void MacroAssembler::LoadGlobalProxy(Register dst) {
+  lw(dst, GlobalObjectOperand());
+  lw(dst, FieldMemOperand(dst, GlobalObject::kGlobalProxyOffset));
+}
+
+
 void MacroAssembler::LoadTransitionedArrayMapConditional(
     ElementsKind expected_kind,
     ElementsKind transitioned_kind,
 void MacroAssembler::LoadTransitionedArrayMapConditional(
     ElementsKind expected_kind,
     ElementsKind transitioned_kind,
@@ -5168,6 +5175,19 @@ void MacroAssembler::AssertName(Register object) {
 }
 
 
 }
 
 
+void MacroAssembler::AssertFunction(Register object) {
+  if (emit_debug_code()) {
+    STATIC_ASSERT(kSmiTag == 0);
+    SmiTst(object, t0);
+    Check(ne, kOperandIsASmiAndNotAFunction, t0, Operand(zero_reg));
+    push(object);
+    GetObjectType(object, object, object);
+    pop(object);
+    Check(eq, kOperandIsNotAFunction, object, Operand(JS_FUNCTION_TYPE));
+  }
+}
+
+
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
                                                      Register scratch) {
   if (emit_debug_code()) {
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
                                                      Register scratch) {
   if (emit_debug_code()) {
index 5e1d2c6253c2022fad0ab860ec85bde1f13c580e..96eb9b4105d3b2740dbb722b8753539de0bbf1a1 100644 (file)
@@ -292,6 +292,24 @@ class MacroAssembler: public Assembler {
   void Load(Register dst, const MemOperand& src, Representation r);
   void Store(Register src, const MemOperand& dst, Representation r);
 
   void Load(Register dst, const MemOperand& src, Representation r);
   void Store(Register src, const MemOperand& dst, Representation r);
 
+  void PushRoot(Heap::RootListIndex index) {
+    LoadRoot(at, index);
+    Push(at);
+  }
+
+  // Compare the object in a register to a value and jump if they are equal.
+  void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal) {
+    LoadRoot(at, index);
+    Branch(if_equal, eq, with, Operand(at));
+  }
+
+  // Compare the object in a register to a value and jump if they are not equal.
+  void JumpIfNotRoot(Register with, Heap::RootListIndex index,
+                     Label* if_not_equal) {
+    LoadRoot(at, index);
+    Branch(if_not_equal, ne, with, Operand(at));
+  }
+
   // Load an object from the root table.
   void LoadRoot(Register destination,
                 Heap::RootListIndex index);
   // Load an object from the root table.
   void LoadRoot(Register destination,
                 Heap::RootListIndex index);
@@ -923,6 +941,9 @@ class MacroAssembler: public Assembler {
 
   void LoadContext(Register dst, int context_chain_length);
 
 
   void LoadContext(Register dst, int context_chain_length);
 
+  // Load the global proxy from the current context.
+  void LoadGlobalProxy(Register dst);
+
   // Conditionally load the cached Array transitioned map of type
   // transitioned_kind from the native context if the map in register
   // map_in_out is the cached Array map in the native context of
   // Conditionally load the cached Array transitioned map of type
   // transitioned_kind from the native context if the map in register
   // map_in_out is the cached Array map in the native context of
@@ -1464,6 +1485,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
+  // Abort execution if argument is not a JSFunction, enabled via --debug-code.
+  void AssertFunction(Register object);
+
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object, Register scratch);
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object, Register scratch);
index 3c0a32667e0cfd6f3bd4f61e6ee65e7ff27101ae..655d5904d043c6b7f6ad598e6988fdd700151135 100644 (file)
@@ -1249,128 +1249,31 @@ void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
 }
 
 
 }
 
 
+// static
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
   // 1. Make sure we have at least one argument.
   // a0: actual number of arguments
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
   // 1. Make sure we have at least one argument.
   // a0: actual number of arguments
-  { Label done;
+  {
+    Label done;
     __ Branch(&done, ne, a0, Operand(zero_reg));
     __ Branch(&done, ne, a0, Operand(zero_reg));
-    __ LoadRoot(a6, Heap::kUndefinedValueRootIndex);
-    __ push(a6);
+    __ PushRoot(Heap::kUndefinedValueRootIndex);
     __ Daddu(a0, a0, Operand(1));
     __ bind(&done);
   }
 
     __ Daddu(a0, a0, Operand(1));
     __ bind(&done);
   }
 
-  // 2. Get the function to call (passed as receiver) from the stack, check
-  //    if it is a function.
+  // 2. Get the function to call (passed as receiver) from the stack.
   // a0: actual number of arguments
   // a0: actual number of arguments
-  Label slow, non_function;
   __ dsll(at, a0, kPointerSizeLog2);
   __ daddu(at, sp, at);
   __ ld(a1, MemOperand(at));
   __ dsll(at, a0, kPointerSizeLog2);
   __ daddu(at, sp, at);
   __ ld(a1, MemOperand(at));
-  __ JumpIfSmi(a1, &non_function);
-  __ GetObjectType(a1, a2, a2);
-  __ 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(a4, Operand(0, RelocInfo::NONE32));  // Indicate regular JS_FUNCTION.
-  { Label convert_to_object, use_global_proxy, patch_receiver;
-    // Change context eagerly in case we need the global receiver.
-    __ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
-
-    // Do not transform the receiver for strict mode functions.
-    __ ld(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
-    __ lbu(a3, FieldMemOperand(a2, SharedFunctionInfo::kStrictModeByteOffset));
-    __ And(a7, a3, Operand(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
-    __ Branch(&shift_arguments, ne, a7, Operand(zero_reg));
-
-    // Do not transform the receiver for native (Compilerhints already in a3).
-    __ lbu(a3, FieldMemOperand(a2, SharedFunctionInfo::kNativeByteOffset));
-    __ And(a7, a3, Operand(1 << SharedFunctionInfo::kNativeBitWithinByte));
-    __ Branch(&shift_arguments, ne, a7, Operand(zero_reg));
-
-    // Compute the receiver in sloppy mode.
-    // Load first argument in a2. a2 = -kPointerSize(sp + n_args << 2).
-    __ dsll(at, a0, kPointerSizeLog2);
-    __ daddu(a2, sp, at);
-    __ ld(a2, MemOperand(a2, -kPointerSize));
-    // a0: actual number of arguments
-    // a1: function
-    // a2: first argument
-    __ JumpIfSmi(a2, &convert_to_object, a6);
-
-    __ LoadRoot(a3, Heap::kUndefinedValueRootIndex);
-    __ Branch(&use_global_proxy, eq, a2, Operand(a3));
-    __ LoadRoot(a3, Heap::kNullValueRootIndex);
-    __ Branch(&use_global_proxy, eq, a2, Operand(a3));
-
-    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
-    __ GetObjectType(a2, a3, a3);
-    __ Branch(&shift_arguments, ge, a3, Operand(FIRST_SPEC_OBJECT_TYPE));
-
-    __ bind(&convert_to_object);
-    // Enter an internal frame in order to preserve argument count.
-    {
-      FrameScope scope(masm, StackFrame::INTERNAL);
-      __ SmiTag(a0);
-      __ Push(a0);
-      __ mov(a0, a2);
-      ToObjectStub stub(masm->isolate());
-      __ CallStub(&stub);
-      __ mov(a2, v0);
-
-      __ pop(a0);
-      __ SmiUntag(a0);
-      // Leave internal frame.
-    }
-    // Restore the function to a1, and the flag to a4.
-    __ dsll(at, a0, kPointerSizeLog2);
-    __ daddu(at, sp, at);
-    __ ld(a1, MemOperand(at));
-    __ Branch(USE_DELAY_SLOT, &patch_receiver);
-    __ li(a4, Operand(0, RelocInfo::NONE32));
-
-    __ bind(&use_global_proxy);
-    __ ld(a2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
-    __ ld(a2, FieldMemOperand(a2, GlobalObject::kGlobalProxyOffset));
-
-    __ bind(&patch_receiver);
-    __ dsll(at, a0, kPointerSizeLog2);
-    __ daddu(a3, sp, at);
-    __ sd(a2, MemOperand(a3, -kPointerSize));
-
-    __ Branch(&shift_arguments);
-  }
-
-  // 3b. Check for function proxy.
-  __ bind(&slow);
-  __ li(a4, Operand(1, RelocInfo::NONE32));  // Indicate function proxy.
-  __ Branch(&shift_arguments, eq, a2, Operand(JS_FUNCTION_PROXY_TYPE));
 
 
-  __ bind(&non_function);
-  __ li(a4, Operand(2, RelocInfo::NONE32));  // 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
-  // a4: call type (0: JS function, 1: function proxy, 2: non-function)
-  __ dsll(at, a0, kPointerSizeLog2);
-  __ daddu(a2, sp, at);
-  __ sd(a1, MemOperand(a2, -kPointerSize));
-
-  // 4. Shift arguments and return address one slot down on the stack
+  // 3. 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
   //    (overwriting the original receiver).  Adjust argument count to make
   //    the original first argument the new receiver.
   // a0: actual number of arguments
   // a1: function
-  // a4: call type (0: JS function, 1: function proxy, 2: non-function)
-  __ bind(&shift_arguments);
-  { Label loop;
+  {
+    Label loop;
     // Calculate the copy start address (destination). Copy end address is sp.
     __ dsll(at, a0, kPointerSizeLog2);
     __ daddu(a2, sp, at);
     // Calculate the copy start address (destination). Copy end address is sp.
     __ dsll(at, a0, kPointerSizeLog2);
     __ daddu(a2, sp, at);
@@ -1386,47 +1289,8 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
     __ Pop();
   }
 
     __ Pop();
   }
 
-  // 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
-  // a4: call type (0: JS function, 1: function proxy, 2: non-function)
-  { Label function, non_proxy;
-    __ Branch(&function, eq, a4, Operand(zero_reg));
-    // Expected number of arguments is 0 for CALL_NON_FUNCTION.
-    __ mov(a2, zero_reg);
-    __ Branch(&non_proxy, ne, a4, Operand(1));
-
-    __ push(a1);  // Re-add proxy object as additional argument.
-    __ Daddu(a0, a0, Operand(1));
-    __ GetBuiltinFunction(a1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-            RelocInfo::CODE_TARGET);
-
-    __ bind(&non_proxy);
-    __ GetBuiltinFunction(a1, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-    __ Jump(masm->isolate()->builtins()->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.
-  // a0: actual number of arguments
-  // a1: function
-  __ ld(a3, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
-  // The argument count is stored as int32_t on 64-bit platforms.
-  // TODO(plind): Smi on 32-bit platforms.
-  __ lw(a2,
-         FieldMemOperand(a3, SharedFunctionInfo::kFormalParameterCountOffset));
-  // Check formal and actual parameter counts.
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET, ne, a2, Operand(a0));
-
-  __ ld(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
-  ParameterCount expected(0);
-  __ InvokeCode(a3, expected, expected, JUMP_FUNCTION, NullCallWrapper());
+  // 4. Call the callable.
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -1490,9 +1354,8 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
     const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
     __ ld(a0, MemOperand(fp, kFunctionOffset));  // Get the function.
     const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
     __ ld(a0, MemOperand(fp, kFunctionOffset));  // Get the function.
-    __ push(a0);
-    __ ld(a0, MemOperand(fp, kArgumentsOffset));  // Get the args array.
-    __ push(a0);
+    __ ld(a1, MemOperand(fp, kArgumentsOffset));  // Get the args array.
+    __ Push(a0, a1);
 
     // Returns (in v0) number of arguments to copy to stack as Smi.
     if (targetIsArgument) {
 
     // Returns (in v0) number of arguments to copy to stack as Smi.
     if (targetIsArgument) {
@@ -1511,89 +1374,18 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
     const int kLimitOffset =
         StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
     __ mov(a1, zero_reg);
     const int kLimitOffset =
         StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
     __ mov(a1, zero_reg);
-    __ Push(v0, a1);  // Limit and initial index.
-
-    // Get the receiver.
-    __ ld(a0, MemOperand(fp, kReceiverOffset));
-
-    // Check that the function is a JS function (otherwise it must be a proxy).
-    Label push_receiver;
-    __ ld(a1, MemOperand(fp, kFunctionOffset));
-    __ GetObjectType(a1, a2, a2);
-    __ Branch(&push_receiver, ne, a2, Operand(JS_FUNCTION_TYPE));
-
-    // Change context eagerly to get the right global object if necessary.
-    __ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
-    // Load the shared function info while the function is still in a1.
-    __ ld(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
-
-    // Compute the receiver.
-    // Do not transform the receiver for strict mode functions.
-    Label call_to_object, use_global_proxy;
-    __ lbu(a7, FieldMemOperand(a2, SharedFunctionInfo::kStrictModeByteOffset));
-    __ And(a7, a7, Operand(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
-    __ Branch(&push_receiver, ne, a7, Operand(zero_reg));
-
-    // Do not transform the receiver for native (Compilerhints already in a2).
-    __ lbu(a7, FieldMemOperand(a2, SharedFunctionInfo::kNativeByteOffset));
-    __ And(a7, a7, Operand(1 << SharedFunctionInfo::kNativeBitWithinByte));
-    __ Branch(&push_receiver, ne, a7, Operand(zero_reg));
-
-    // Compute the receiver in sloppy mode.
-    __ JumpIfSmi(a0, &call_to_object);
-    __ LoadRoot(a1, Heap::kNullValueRootIndex);
-    __ Branch(&use_global_proxy, eq, a0, Operand(a1));
-    __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
-    __ Branch(&use_global_proxy, 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);
-    ToObjectStub stub(masm->isolate());
-    __ CallStub(&stub);
-    __ mov(a0, v0);  // Put object in a0 to match other paths to push_receiver.
-    __ Branch(&push_receiver);
-
-    __ bind(&use_global_proxy);
-    __ ld(a0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
-    __ ld(a0, FieldMemOperand(a0, GlobalObject::kGlobalProxyOffset));
-
-    // Push the receiver.
-    // a0: receiver
-    __ bind(&push_receiver);
-    __ push(a0);
+    __ ld(a2, MemOperand(fp, kReceiverOffset));
+    __ Push(v0, a1, a2);  // limit, initial index and receiver.
 
     // Copy all arguments from the array to the stack.
 
     // Copy all arguments from the array to the stack.
-    Generate_PushAppliedArguments(
-        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+    Generate_PushAppliedArguments(masm, kArgumentsOffset, kIndexOffset,
+                                  kLimitOffset);
 
 
-    // Call the function.
-    Label call_proxy;
-    ParameterCount actual(a0);
+    // Call the callable.
+    // TODO(bmeurer): This should be a tail call according to ES6.
     __ ld(a1, MemOperand(fp, kFunctionOffset));
     __ ld(a1, MemOperand(fp, kFunctionOffset));
-    __ GetObjectType(a1, a2, a2);
-    __ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE));
-
-    __ InvokeFunction(a1, actual, CALL_FUNCTION, NullCallWrapper());
-
-    frame_scope.GenerateLeaveFrame();
-    __ Ret(USE_DELAY_SLOT);
-    __ Daddu(sp, sp, Operand(kStackSize * kPointerSize));  // In delay slot.
+    __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 
 
-    // Call the function proxy.
-    __ bind(&call_proxy);
-    __ push(a1);  // Add function proxy as last argument.
-    __ Daddu(a0, a0, Operand(1));
-    __ li(a2, Operand(0, RelocInfo::NONE32));
-    __ GetBuiltinFunction(a1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-            RelocInfo::CODE_TARGET);
     // Tear down the internal frame and remove function, receiver and args.
   }
 
     // Tear down the internal frame and remove function, receiver and args.
   }
 
@@ -1730,6 +1522,145 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
 }
 
 
 }
 
 
+// static
+void Builtins::Generate_CallFunction(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- a0 : the number of arguments (not including the receiver)
+  //  -- a1 : the function to call (checked to be a JSFunction)
+  // -----------------------------------
+
+  Label convert, convert_global_proxy, convert_to_object, done_convert;
+  __ AssertFunction(a1);
+  // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal
+  // slot is "classConstructor".
+  // Enter the context of the function; ToObject has to run in the function
+  // context, and we also need to take the global proxy from the function
+  // context in case of conversion.
+  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
+  STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
+                SharedFunctionInfo::kStrictModeByteOffset);
+  __ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
+  __ ld(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+  // We need to convert the receiver for non-native sloppy mode functions.
+  __ lbu(a3, FieldMemOperand(a2, SharedFunctionInfo::kNativeByteOffset));
+  __ And(at, a3, Operand((1 << SharedFunctionInfo::kNativeBitWithinByte) |
+                         (1 << SharedFunctionInfo::kStrictModeBitWithinByte)));
+  __ Branch(&done_convert, ne, at, Operand(zero_reg));
+  {
+    __ dsll(at, a0, kPointerSizeLog2);
+    __ daddu(at, sp, at);
+    __ ld(a3, MemOperand(at));
+
+    // ----------- S t a t e -------------
+    //  -- a0 : the number of arguments (not including the receiver)
+    //  -- a1 : the function to call (checked to be a JSFunction)
+    //  -- a2 : the shared function info.
+    //  -- a3 : the receiver
+    //  -- cp : the function context.
+    // -----------------------------------
+
+    Label convert_receiver;
+    __ JumpIfSmi(a3, &convert_to_object);
+    STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+    __ GetObjectType(a3, a4, a4);
+    __ Branch(&done_convert, hs, a4, Operand(FIRST_JS_RECEIVER_TYPE));
+    __ JumpIfRoot(a3, Heap::kUndefinedValueRootIndex, &convert_global_proxy);
+    __ JumpIfNotRoot(a3, Heap::kNullValueRootIndex, &convert_to_object);
+    __ bind(&convert_global_proxy);
+    {
+      // Patch receiver to global proxy.
+      __ LoadGlobalProxy(a3);
+    }
+    __ Branch(&convert_receiver);
+    __ bind(&convert_to_object);
+    {
+      // Convert receiver using ToObject.
+      // TODO(bmeurer): Inline the allocation here to avoid building the frame
+      // in the fast case? (fall back to AllocateInNewSpace?)
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      __ SmiTag(a0);
+      __ Push(a0, a1);
+      __ mov(a0, a3);
+      ToObjectStub stub(masm->isolate());
+      __ CallStub(&stub);
+      __ mov(a3, v0);
+      __ Pop(a0, a1);
+      __ SmiUntag(a0);
+    }
+    __ ld(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+    __ bind(&convert_receiver);
+    __ dsll(at, a0, kPointerSizeLog2);
+    __ daddu(at, sp, at);
+    __ sd(a3, MemOperand(at));
+  }
+  __ bind(&done_convert);
+
+  // ----------- S t a t e -------------
+  //  -- a0 : the number of arguments (not including the receiver)
+  //  -- a1 : the function to call (checked to be a JSFunction)
+  //  -- a2 : the shared function info.
+  //  -- cp : the function context.
+  // -----------------------------------
+
+  __ lw(a2,
+        FieldMemOperand(a2, SharedFunctionInfo::kFormalParameterCountOffset));
+  __ ld(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
+  ParameterCount actual(a0);
+  ParameterCount expected(a2);
+  __ InvokeCode(a3, expected, actual, JUMP_FUNCTION, NullCallWrapper());
+}
+
+
+// static
+void Builtins::Generate_Call(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- a0 : the number of arguments (not including the receiver)
+  //  -- a1 : the target to call (can be any Object).
+  // -----------------------------------
+
+  Label non_smi, non_function;
+  __ JumpIfSmi(a1, &non_function);
+  __ bind(&non_smi);
+  __ GetObjectType(a1, a2, a2);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
+          eq, a2, Operand(JS_FUNCTION_TYPE));
+  __ Branch(&non_function, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE));
+
+  // 1. Call to function proxy.
+  // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
+  __ ld(a1, FieldMemOperand(a1, JSFunctionProxy::kCallTrapOffset));
+  __ AssertNotSmi(a1);
+  __ Branch(&non_smi);
+
+  // 2. Call to something else, which might have a [[Call]] internal method (if
+  // not we raise an exception).
+  __ bind(&non_function);
+  // TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
+  // be awesome instead; i.e. a trivial improvement would be to call into the
+  // runtime and just deal with the API function there instead of returning a
+  // delegate from a runtime call that just jumps back to the runtime once
+  // called. Or, bonus points, call directly into the C API function here, as
+  // we do in some Crankshaft fast cases.
+  // Overwrite the original receiver with the (original) target.
+  __ dsll(at, a0, kPointerSizeLog2);
+  __ daddu(at, sp, at);
+  __ sd(a1, MemOperand(at));
+  {
+    // Determine the delegate for the target (if any).
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    __ SmiTag(a0);
+    __ Push(a0, a1);
+    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
+    __ mov(a1, v0);
+    __ Pop(a0);
+    __ SmiUntag(a0);
+  }
+  // The delegate is always a regular function.
+  __ AssertFunction(a1);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+}
+
+
 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
   // State setup as expected by MacroAssembler::InvokePrologue.
   // ----------- S t a t e -------------
 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
   // State setup as expected by MacroAssembler::InvokePrologue.
   // ----------- S t a t e -------------
index 8360b07f8fa7ccfa21bded18eee1fd02e061081b..6d5b446e661d705c268352a42ca7544e78431aae 100644 (file)
@@ -2562,30 +2562,9 @@ static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
 }
 
 
 }
 
 
-static void EmitSlowCase(MacroAssembler* masm,
-                         int argc,
-                         Label* non_function) {
-  // Check for function proxy.
-  __ Branch(non_function, ne, a4, Operand(JS_FUNCTION_PROXY_TYPE));
-  __ push(a1);  // put proxy as additional argument
-  __ li(a0, Operand(argc + 1, RelocInfo::NONE32));
-  __ mov(a2, zero_reg);
-  __ GetBuiltinFunction(a1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-  {
-    Handle<Code> adaptor =
-        masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
-    __ Jump(adaptor, RelocInfo::CODE_TARGET);
-  }
-
-  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
-  // of the original receiver from the call site).
-  __ bind(non_function);
-  __ sd(a1, MemOperand(sp, argc * kPointerSize));
-  __ li(a0, Operand(argc));  // Set up the number of arguments.
-  __ mov(a2, zero_reg);
-  __ GetBuiltinFunction(a1, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET);
+static void EmitSlowCase(MacroAssembler* masm, int argc) {
+  __ li(a0, Operand(argc));
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -2607,12 +2586,12 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
                                    int argc, bool needs_checks,
                                    bool call_as_method) {
   // a1 : the function to call
                                    int argc, bool needs_checks,
                                    bool call_as_method) {
   // a1 : the function to call
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
 
   if (needs_checks) {
     // Check that the function is really a JavaScript function.
     // a1: pushed function (to be verified)
 
   if (needs_checks) {
     // Check that the function is really a JavaScript function.
     // a1: pushed function (to be verified)
-    __ JumpIfSmi(a1, &non_function);
+    __ JumpIfSmi(a1, &slow);
 
     // Goto slow case if we do not have a function.
     __ GetObjectType(a1, a4, a4);
 
     // Goto slow case if we do not have a function.
     __ GetObjectType(a1, a4, a4);
@@ -2646,7 +2625,7 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ bind(&slow);
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ bind(&slow);
-    EmitSlowCase(masm, argc, &non_function);
+    EmitSlowCase(masm, argc);
   }
 
   if (call_as_method) {
   }
 
   if (call_as_method) {
@@ -2819,13 +2798,8 @@ void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
-  CallFunctionNoFeedback(masm,
-                         arg_count(),
-                         true,
-                         CallAsMethod());
-
-  // Unreachable.
-  __ stop("Unexpected code address");
+  __ li(a0, Operand(arg_count()));
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -2838,7 +2812,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
   Label have_js_function;
   int argc = arg_count();
   ParameterCount actual(argc);
   Label have_js_function;
   int argc = arg_count();
   ParameterCount actual(argc);
@@ -2892,7 +2866,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   __ InvokeFunction(a1, actual, JUMP_FUNCTION, NullCallWrapper());
 
   __ bind(&slow);
   __ InvokeFunction(a1, actual, JUMP_FUNCTION, NullCallWrapper());
 
   __ bind(&slow);
-  EmitSlowCase(masm, argc, &non_function);
+  EmitSlowCase(masm, argc);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
@@ -2979,8 +2953,8 @@ void CallICStub::Generate(MacroAssembler* masm) {
   // the slow case
   __ bind(&slow_start);
   // Check that the function is really a JavaScript function.
   // the slow case
   __ bind(&slow_start);
   // Check that the function is really a JavaScript function.
-  // r1: pushed function (to be verified)
-  __ JumpIfSmi(a1, &non_function);
+  // a1: pushed function (to be verified)
+  __ JumpIfSmi(a1, &slow);
 
   // Goto slow case if we do not have a function.
   __ GetObjectType(a1, a4, a4);
 
   // Goto slow case if we do not have a function.
   __ GetObjectType(a1, a4, a4);
index a379d847ae597d4e6afe2600ef1b44b39aa89dd8..d1f8bf396e2dc93ca5eb71fb59f33101a4f30b14 100644 (file)
@@ -4874,6 +4874,12 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
 }
 
 
 }
 
 
+void MacroAssembler::LoadGlobalProxy(Register dst) {
+  ld(dst, GlobalObjectOperand());
+  ld(dst, FieldMemOperand(dst, GlobalObject::kGlobalProxyOffset));
+}
+
+
 void MacroAssembler::LoadTransitionedArrayMapConditional(
     ElementsKind expected_kind,
     ElementsKind transitioned_kind,
 void MacroAssembler::LoadTransitionedArrayMapConditional(
     ElementsKind expected_kind,
     ElementsKind transitioned_kind,
@@ -5367,6 +5373,19 @@ void MacroAssembler::AssertName(Register object) {
 }
 
 
 }
 
 
+void MacroAssembler::AssertFunction(Register object) {
+  if (emit_debug_code()) {
+    STATIC_ASSERT(kSmiTag == 0);
+    SmiTst(object, t0);
+    Check(ne, kOperandIsASmiAndNotAFunction, t0, Operand(zero_reg));
+    push(object);
+    GetObjectType(object, object, object);
+    pop(object);
+    Check(eq, kOperandIsNotAFunction, object, Operand(JS_FUNCTION_TYPE));
+  }
+}
+
+
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
                                                      Register scratch) {
   if (emit_debug_code()) {
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
                                                      Register scratch) {
   if (emit_debug_code()) {
index 17e0857ba59d905ffb7203741d7be7965c1d60ae..b374d43b797742b54f33bf2b547c23561cf3d776 100644 (file)
@@ -313,6 +313,24 @@ class MacroAssembler: public Assembler {
   void Load(Register dst, const MemOperand& src, Representation r);
   void Store(Register src, const MemOperand& dst, Representation r);
 
   void Load(Register dst, const MemOperand& src, Representation r);
   void Store(Register src, const MemOperand& dst, Representation r);
 
+  void PushRoot(Heap::RootListIndex index) {
+    LoadRoot(at, index);
+    Push(at);
+  }
+
+  // Compare the object in a register to a value and jump if they are equal.
+  void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal) {
+    LoadRoot(at, index);
+    Branch(if_equal, eq, with, Operand(at));
+  }
+
+  // Compare the object in a register to a value and jump if they are not equal.
+  void JumpIfNotRoot(Register with, Heap::RootListIndex index,
+                     Label* if_not_equal) {
+    LoadRoot(at, index);
+    Branch(if_not_equal, ne, with, Operand(at));
+  }
+
   // Load an object from the root table.
   void LoadRoot(Register destination,
                 Heap::RootListIndex index);
   // Load an object from the root table.
   void LoadRoot(Register destination,
                 Heap::RootListIndex index);
@@ -953,6 +971,9 @@ class MacroAssembler: public Assembler {
 
   void LoadContext(Register dst, int context_chain_length);
 
 
   void LoadContext(Register dst, int context_chain_length);
 
+  // Load the global proxy from the current context.
+  void LoadGlobalProxy(Register dst);
+
   // Conditionally load the cached Array transitioned map of type
   // transitioned_kind from the native context if the map in register
   // map_in_out is the cached Array map in the native context of
   // Conditionally load the cached Array transitioned map of type
   // transitioned_kind from the native context if the map in register
   // map_in_out is the cached Array map in the native context of
@@ -1557,6 +1578,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
+  // Abort execution if argument is not a JSFunction, enabled via --debug-code.
+  void AssertFunction(Register object);
+
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object, Register scratch);
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object, Register scratch);
index 4ece658d38414e1f6d9e308bfb9977a7c647c6e8..dd43f0fe5b08df6f813d7fabd23ed9880c8d1a33 100644 (file)
@@ -6705,12 +6705,12 @@ class SharedFunctionInfo: public HeapObject {
     kAllowLazyCompilation,
     kAllowLazyCompilationWithoutContext,
     kOptimizationDisabled,
     kAllowLazyCompilation,
     kAllowLazyCompilationWithoutContext,
     kOptimizationDisabled,
+    kNative,
     kStrictModeFunction,
     kStrongModeFunction,
     kUsesArguments,
     kNeedsHomeObject,
     kHasDuplicateParameters,
     kStrictModeFunction,
     kStrongModeFunction,
     kUsesArguments,
     kNeedsHomeObject,
     kHasDuplicateParameters,
-    kNative,
     kForceInline,
     kBoundFunction,
     kIsAnonymous,
     kForceInline,
     kBoundFunction,
     kIsAnonymous,
index b2e902288946dbbfa0ef77e359ba38c66a124057..82c668a6e26438475b00f59cacb0b2ceb2788836 100644 (file)
@@ -424,26 +424,12 @@ function SHR_STRONG(y) {
    -----------------------------
 */
 
    -----------------------------
 */
 
-function CALL_NON_FUNCTION() {
-  var delegate = %GetFunctionDelegate(this);
-  return %Apply(delegate, this, arguments, 0, %_ArgumentsLength());
-}
-
-
 function CALL_NON_FUNCTION_AS_CONSTRUCTOR() {
   var delegate = %GetConstructorDelegate(this);
   return %Apply(delegate, this, arguments, 0, %_ArgumentsLength());
 }
 
 
 function CALL_NON_FUNCTION_AS_CONSTRUCTOR() {
   var delegate = %GetConstructorDelegate(this);
   return %Apply(delegate, this, arguments, 0, %_ArgumentsLength());
 }
 
 
-function CALL_FUNCTION_PROXY() {
-  var arity = %_ArgumentsLength() - 1;
-  var proxy = %_Arguments(arity);  // The proxy comes in as an additional arg.
-  var trap = %GetCallTrap(proxy);
-  return %Apply(trap, this, arguments, 0, arity);
-}
-
-
 function CALL_FUNCTION_PROXY_AS_CONSTRUCTOR () {
   var proxy = this;
   var trap = %GetConstructTrap(proxy);
 function CALL_FUNCTION_PROXY_AS_CONSTRUCTOR () {
   var proxy = this;
   var trap = %GetConstructTrap(proxy);
@@ -453,13 +439,19 @@ function CALL_FUNCTION_PROXY_AS_CONSTRUCTOR () {
 
 function APPLY_PREPARE(args) {
   var length;
 
 function APPLY_PREPARE(args) {
   var length;
+
+  // First check that the receiver is callable.
+  if (!IS_CALLABLE(this)) {
+    throw %make_type_error(kApplyNonFunction, %to_string_fun(this),
+                           typeof this);
+  }
+
   // First check whether length is a positive Smi and args is an
   // array. This is the fast case. If this fails, we do the slow case
   // that takes care of more eventualities.
   if (IS_ARRAY(args)) {
     length = args.length;
   // First check whether length is a positive Smi and args is an
   // array. This is the fast case. If this fails, we do the slow case
   // that takes care of more eventualities.
   if (IS_ARRAY(args)) {
     length = args.length;
-    if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength &&
-        IS_CALLABLE(this)) {
+    if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength) {
       return length;
     }
   }
       return length;
     }
   }
@@ -471,11 +463,6 @@ function APPLY_PREPARE(args) {
   // multiplying with pointer size.
   if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow);
 
   // multiplying with pointer size.
   if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow);
 
-  if (!IS_CALLABLE(this)) {
-    throw %make_type_error(kApplyNonFunction, %to_string_fun(this),
-                           typeof this);
-  }
-
   // Make sure the arguments list has the right type.
   if (args != null && !IS_SPEC_OBJECT(args)) {
     throw %make_type_error(kWrongArgs, "Function.prototype.apply");
   // Make sure the arguments list has the right type.
   if (args != null && !IS_SPEC_OBJECT(args)) {
     throw %make_type_error(kWrongArgs, "Function.prototype.apply");
@@ -489,21 +476,23 @@ function APPLY_PREPARE(args) {
 
 function REFLECT_APPLY_PREPARE(args) {
   var length;
 
 function REFLECT_APPLY_PREPARE(args) {
   var length;
+
+  // First check that the receiver is callable.
+  if (!IS_CALLABLE(this)) {
+    throw %make_type_error(kApplyNonFunction, %to_string_fun(this),
+                           typeof this);
+  }
+
   // First check whether length is a positive Smi and args is an
   // array. This is the fast case. If this fails, we do the slow case
   // that takes care of more eventualities.
   if (IS_ARRAY(args)) {
     length = args.length;
   // First check whether length is a positive Smi and args is an
   // array. This is the fast case. If this fails, we do the slow case
   // that takes care of more eventualities.
   if (IS_ARRAY(args)) {
     length = args.length;
-    if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength &&
-        IS_CALLABLE(this)) {
+    if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength) {
       return length;
     }
   }
 
       return length;
     }
   }
 
-  if (!IS_CALLABLE(this)) {
-    throw %make_type_error(kCalledNonCallable, %to_string_fun(this));
-  }
-
   if (!IS_SPEC_OBJECT(args)) {
     throw %make_type_error(kWrongArgs, "Reflect.apply");
   }
   if (!IS_SPEC_OBJECT(args)) {
     throw %make_type_error(kWrongArgs, "Reflect.apply");
   }
@@ -802,9 +791,7 @@ $toString = ToString;
   "bit_xor_builtin", BIT_XOR,
   "bit_xor_strong_builtin", BIT_XOR_STRONG,
   "call_function_proxy_as_constructor_builtin", CALL_FUNCTION_PROXY_AS_CONSTRUCTOR,
   "bit_xor_builtin", BIT_XOR,
   "bit_xor_strong_builtin", BIT_XOR_STRONG,
   "call_function_proxy_as_constructor_builtin", CALL_FUNCTION_PROXY_AS_CONSTRUCTOR,
-  "call_function_proxy_builtin", CALL_FUNCTION_PROXY,
   "call_non_function_as_constructor_builtin", CALL_NON_FUNCTION_AS_CONSTRUCTOR,
   "call_non_function_as_constructor_builtin", CALL_NON_FUNCTION_AS_CONSTRUCTOR,
-  "call_non_function_builtin", CALL_NON_FUNCTION,
   "compare_builtin", COMPARE,
   "compare_strong_builtin", COMPARE_STRONG,
   "concat_iterable_to_array_builtin", CONCAT_ITERABLE_TO_ARRAY,
   "compare_builtin", COMPARE,
   "compare_strong_builtin", COMPARE_STRONG,
   "concat_iterable_to_array_builtin", CONCAT_ITERABLE_TO_ARRAY,
index a00ca4b73a7728436145eedee8c9c7ff6170f29b..51befeedbb6d7ebcfea2f1a13cb38d5f696704ee 100644 (file)
@@ -16,6 +16,9 @@
 namespace v8 {
 namespace internal {
 
 namespace v8 {
 namespace internal {
 
+// TODO(bmeurer): This is an awful hack resulting from our inability to decide
+// who's responsible for doing the receiver patching. By any means, we really
+// need to kill this runtime function and just do things right instead!!
 RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
 RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
index eaae88aa3780639d30a27601499595a17a9e7701..9012cab3bb0905b967d51f094ab23645f5aad345 100644 (file)
@@ -1003,6 +1003,7 @@ void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
 }
 
 
 }
 
 
+// static
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
   // Stack Layout:
   // rsp[0]           : Return address
 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
   // Stack Layout:
   // rsp[0]           : Return address
@@ -1010,162 +1011,46 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
   // rsp[16]          : Argument n-1
   //  ...
   // rsp[8 * n]       : Argument 1
   // rsp[16]          : Argument n-1
   //  ...
   // rsp[8 * n]       : Argument 1
-  // rsp[8 * (n + 1)] : Receiver (function to call)
+  // rsp[8 * (n + 1)] : Receiver (callable to call)
   //
   // rax contains the number of arguments, n, not counting the receiver.
   //
   // 1. Make sure we have at least one argument.
   //
   // rax contains the number of arguments, n, not counting the receiver.
   //
   // 1. Make sure we have at least one argument.
-  { Label done;
+  {
+    Label done;
     __ testp(rax, rax);
     __ testp(rax, rax);
-    __ j(not_zero, &done);
+    __ j(not_zero, &done, Label::kNear);
     __ PopReturnAddressTo(rbx);
     __ PopReturnAddressTo(rbx);
-    __ Push(masm->isolate()->factory()->undefined_value());
+    __ PushRoot(Heap::kUndefinedValueRootIndex);
     __ PushReturnAddressFrom(rbx);
     __ incp(rax);
     __ bind(&done);
   }
 
     __ PushReturnAddressFrom(rbx);
     __ incp(rax);
     __ bind(&done);
   }
 
-  // 2. Get the function to call (passed as receiver) from the stack, check
-  //    if it is a function.
-  Label slow, non_function;
-  StackArgumentsAccessor args(rsp, rax);
-  __ movp(rdi, args.GetReceiverOperand());
-  __ JumpIfSmi(rdi, &non_function);
-  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
-  __ j(not_equal, &slow);
-
-  // 3a. Patch the first argument if necessary when calling a function.
-  Label shift_arguments;
-  __ Set(rdx, 0);  // indicate regular JS_FUNCTION
-  { Label convert_to_object, use_global_proxy, patch_receiver;
-    // Change context eagerly in case we need the global receiver.
-    __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
-
-    // Do not transform the receiver for strict mode functions.
-    __ movp(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
-    __ testb(FieldOperand(rbx, SharedFunctionInfo::kStrictModeByteOffset),
-             Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
-    __ j(not_equal, &shift_arguments);
-
-    // Do not transform the receiver for natives.
-    // SharedFunctionInfo is already loaded into rbx.
-    __ testb(FieldOperand(rbx, SharedFunctionInfo::kNativeByteOffset),
-             Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
-    __ j(not_zero, &shift_arguments);
-
-    // Compute the receiver in sloppy mode.
-    __ movp(rbx, args.GetArgumentOperand(1));
-    __ JumpIfSmi(rbx, &convert_to_object, Label::kNear);
-
-    __ CompareRoot(rbx, Heap::kNullValueRootIndex);
-    __ j(equal, &use_global_proxy);
-    __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
-    __ j(equal, &use_global_proxy);
-
-    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
-    __ CmpObjectType(rbx, FIRST_SPEC_OBJECT_TYPE, rcx);
-    __ j(above_equal, &shift_arguments);
-
-    __ bind(&convert_to_object);
-    {
-      // Enter an internal frame in order to preserve argument count.
-      FrameScope scope(masm, StackFrame::INTERNAL);
-      __ Integer32ToSmi(rax, rax);
-      __ Push(rax);
-
-      __ movp(rax, rbx);
-      ToObjectStub stub(masm->isolate());
-      __ CallStub(&stub);
-      __ movp(rbx, rax);
-      __ Set(rdx, 0);  // indicate regular JS_FUNCTION
-
-      __ Pop(rax);
-      __ SmiToInteger32(rax, rax);
-    }
-
-    // Restore the function to rdi.
+  // 2. Get the callable to call (passed as receiver) from the stack.
+  {
+    StackArgumentsAccessor args(rsp, rax);
     __ movp(rdi, args.GetReceiverOperand());
     __ movp(rdi, args.GetReceiverOperand());
-    __ jmp(&patch_receiver, Label::kNear);
-
-    __ bind(&use_global_proxy);
-    __ movp(rbx,
-            Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
-    __ movp(rbx, FieldOperand(rbx, GlobalObject::kGlobalProxyOffset));
-
-    __ bind(&patch_receiver);
-    __ movp(args.GetArgumentOperand(1), rbx);
-
-    __ jmp(&shift_arguments);
   }
 
   }
 
-  // 3b. Check for function proxy.
-  __ bind(&slow);
-  __ Set(rdx, 1);  // indicate function proxy
-  __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
-  __ j(equal, &shift_arguments);
-  __ bind(&non_function);
-  __ Set(rdx, 2);  // 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.
-  __ movp(args.GetArgumentOperand(1), rdi);
-
-  // 4. Shift arguments and return address one slot down on the stack
+  // 3. 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.
   //    (overwriting the original receiver).  Adjust argument count to make
   //    the original first argument the new receiver.
-  __ bind(&shift_arguments);
-  { Label loop;
+  {
+    Label loop;
     __ movp(rcx, rax);
     StackArgumentsAccessor args(rsp, rcx);
     __ bind(&loop);
     __ movp(rbx, args.GetArgumentOperand(1));
     __ movp(args.GetArgumentOperand(0), rbx);
     __ decp(rcx);
     __ movp(rcx, rax);
     StackArgumentsAccessor args(rsp, rcx);
     __ bind(&loop);
     __ movp(rbx, args.GetArgumentOperand(1));
     __ movp(args.GetArgumentOperand(0), rbx);
     __ decp(rcx);
-    __ j(not_zero, &loop);  // While non-zero.
+    __ j(not_zero, &loop);              // While non-zero.
     __ DropUnderReturnAddress(1, rbx);  // Drop one slot under return address.
     __ decp(rax);  // One fewer argument (first argument is new receiver).
   }
 
     __ DropUnderReturnAddress(1, rbx);  // Drop one slot under return address.
     __ decp(rax);  // One fewer argument (first argument is new receiver).
   }
 
-  // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
-  //     or a function proxy via CALL_FUNCTION_PROXY.
-  { Label function, non_proxy;
-    __ testp(rdx, rdx);
-    __ j(zero, &function);
-    __ Set(rbx, 0);
-    __ cmpp(rdx, Immediate(1));
-    __ j(not_equal, &non_proxy);
-
-    __ PopReturnAddressTo(rdx);
-    __ Push(rdi);  // re-add proxy object as additional argument
-    __ PushReturnAddressFrom(rdx);
-    __ incp(rax);
-    __ GetBuiltinEntry(rdx, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-           RelocInfo::CODE_TARGET);
-
-    __ bind(&non_proxy);
-    __ GetBuiltinEntry(rdx, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-    __ Jump(masm->isolate()->builtins()->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.
-  __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
-  __ LoadSharedFunctionInfoSpecialField(rbx, rdx,
-      SharedFunctionInfo::kFormalParameterCountOffset);
-  __ movp(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
-  __ cmpp(rax, rbx);
-  __ j(not_equal,
-       masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-       RelocInfo::CODE_TARGET);
-
-  ParameterCount expected(0);
-  __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION, NullCallWrapper());
+  // 4. Call the callable.
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -1251,90 +1136,22 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
 
     Generate_CheckStackOverflow(masm, kFunctionOffset, kRaxIsSmiTagged);
 
 
     Generate_CheckStackOverflow(masm, kFunctionOffset, kRaxIsSmiTagged);
 
-    // Push current index and limit.
+    // Push current index and limit, and receiver.
     const int kLimitOffset =
         StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
     const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
     const int kLimitOffset =
         StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
     const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
-    __ Push(rax);  // limit
-    __ Push(Immediate(0));  // index
-
-    // Get the receiver.
-    __ movp(rbx, Operand(rbp, kReceiverOffset));
-
-    // Check that the function is a JS function (otherwise it must be a proxy).
-    Label push_receiver;
-    __ movp(rdi, Operand(rbp, kFunctionOffset));
-    __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
-    __ j(not_equal, &push_receiver);
-
-    // Change context eagerly to get the right global object if necessary.
-    __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
-
-    // Do not transform the receiver for strict mode functions.
-    Label call_to_object, use_global_proxy;
-    __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
-    __ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset),
-             Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
-    __ j(not_equal, &push_receiver);
-
-    // Do not transform the receiver for natives.
-    __ testb(FieldOperand(rdx, SharedFunctionInfo::kNativeByteOffset),
-             Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
-    __ j(not_equal, &push_receiver);
-
-    // Compute the receiver in sloppy mode.
-    __ JumpIfSmi(rbx, &call_to_object, Label::kNear);
-    __ CompareRoot(rbx, Heap::kNullValueRootIndex);
-    __ j(equal, &use_global_proxy);
-    __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
-    __ j(equal, &use_global_proxy);
-
-    // If given receiver is already a JavaScript object then there's no
-    // reason for converting it.
-    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
-    __ CmpObjectType(rbx, FIRST_SPEC_OBJECT_TYPE, rcx);
-    __ j(above_equal, &push_receiver);
-
-    // Convert the receiver to an object.
-    __ bind(&call_to_object);
-    __ movp(rax, rbx);
-    ToObjectStub stub(masm->isolate());
-    __ CallStub(&stub);
-    __ movp(rbx, rax);
-    __ jmp(&push_receiver, Label::kNear);
-
-    __ bind(&use_global_proxy);
-    __ movp(rbx,
-            Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
-    __ movp(rbx, FieldOperand(rbx, GlobalObject::kGlobalProxyOffset));
-
-    // Push the receiver.
-    __ bind(&push_receiver);
-    __ Push(rbx);
+    __ Push(rax);                            // limit
+    __ Push(Immediate(0));                   // index
+    __ Push(Operand(rbp, kReceiverOffset));  // receiver
 
     // Loop over the arguments array, pushing each value to the stack
 
     // Loop over the arguments array, pushing each value to the stack
-    Generate_PushAppliedArguments(
-        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+    Generate_PushAppliedArguments(masm, kArgumentsOffset, kIndexOffset,
+                                  kLimitOffset);
 
 
-    // Call the function.
-    Label call_proxy;
-    ParameterCount actual(rax);
+    // Call the callable.
+    // TODO(bmeurer): This should be a tail call according to ES6.
     __ movp(rdi, Operand(rbp, kFunctionOffset));
     __ movp(rdi, Operand(rbp, kFunctionOffset));
-    __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
-    __ j(not_equal, &call_proxy);
-    __ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper());
-
-    frame_scope.GenerateLeaveFrame();
-    __ ret(kStackSize * kPointerSize);  // remove this, receiver, and arguments
-
-    // Call the function proxy.
-    __ bind(&call_proxy);
-    __ Push(rdi);  // add function proxy as last argument
-    __ incp(rax);
-    __ Set(rbx, 0);
-    __ GetBuiltinEntry(rdx, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-    __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-            RelocInfo::CODE_TARGET);
+    __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 
     // Leave internal frame.
   }
 
     // Leave internal frame.
   }
@@ -1808,6 +1625,147 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
 }
 
 
 }
 
 
+// static
+void Builtins::Generate_CallFunction(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- rax : the number of arguments (not including the receiver)
+  //  -- rdi : the function to call (checked to be a JSFunction)
+  // -----------------------------------
+
+  Label convert, convert_global_proxy, convert_to_object, done_convert;
+  StackArgumentsAccessor args(rsp, rax);
+  __ AssertFunction(rdi);
+  // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal
+  // slot is "classConstructor".
+  // Enter the context of the function; ToObject has to run in the function
+  // context, and we also need to take the global proxy from the function
+  // context in case of conversion.
+  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
+  STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
+                SharedFunctionInfo::kStrictModeByteOffset);
+  __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+  __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+  // We need to convert the receiver for non-native sloppy mode functions.
+  __ testb(FieldOperand(rdx, SharedFunctionInfo::kNativeByteOffset),
+           Immediate((1 << SharedFunctionInfo::kNativeBitWithinByte) |
+                     (1 << SharedFunctionInfo::kStrictModeBitWithinByte)));
+  __ j(not_zero, &done_convert);
+  {
+    __ movp(rcx, args.GetReceiverOperand());
+
+    // ----------- S t a t e -------------
+    //  -- rax : the number of arguments (not including the receiver)
+    //  -- rcx : the receiver
+    //  -- rdx : the shared function info.
+    //  -- rdi : the function to call (checked to be a JSFunction)
+    //  -- rsi : the function context.
+    // -----------------------------------
+
+    Label convert_receiver;
+    __ JumpIfSmi(rcx, &convert_to_object, Label::kNear);
+    STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+    __ CmpObjectType(rcx, FIRST_JS_RECEIVER_TYPE, rbx);
+    __ j(above_equal, &done_convert);
+    __ JumpIfRoot(rcx, Heap::kUndefinedValueRootIndex, &convert_global_proxy,
+                  Label::kNear);
+    __ JumpIfNotRoot(rcx, Heap::kNullValueRootIndex, &convert_to_object,
+                     Label::kNear);
+    __ bind(&convert_global_proxy);
+    {
+      // Patch receiver to global proxy.
+      __ LoadGlobalProxy(rcx);
+    }
+    __ jmp(&convert_receiver);
+    __ bind(&convert_to_object);
+    {
+      // Convert receiver using ToObject.
+      // TODO(bmeurer): Inline the allocation here to avoid building the frame
+      // in the fast case? (fall back to AllocateInNewSpace?)
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      __ Integer32ToSmi(rax, rax);
+      __ Push(rax);
+      __ Push(rdi);
+      __ movp(rax, rcx);
+      ToObjectStub stub(masm->isolate());
+      __ CallStub(&stub);
+      __ movp(rcx, rax);
+      __ Pop(rdi);
+      __ Pop(rax);
+      __ SmiToInteger32(rax, rax);
+    }
+    __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+    __ bind(&convert_receiver);
+    __ movp(args.GetReceiverOperand(), rcx);
+  }
+  __ bind(&done_convert);
+
+  // ----------- S t a t e -------------
+  //  -- rax : the number of arguments (not including the receiver)
+  //  -- rdx : the shared function info.
+  //  -- rdi : the function to call (checked to be a JSFunction)
+  //  -- rsi : the function context.
+  // -----------------------------------
+
+  __ LoadSharedFunctionInfoSpecialField(
+      rbx, rdx, SharedFunctionInfo::kFormalParameterCountOffset);
+  __ movp(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
+  ParameterCount actual(rax);
+  ParameterCount expected(rbx);
+  __ InvokeCode(rdx, expected, actual, JUMP_FUNCTION, NullCallWrapper());
+}
+
+
+// static
+void Builtins::Generate_Call(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- rax : the number of arguments (not including the receiver)
+  //  -- rdi : the target to call (can be any Object).
+  // -----------------------------------
+
+  Label non_smi, non_function;
+  __ JumpIfSmi(rdi, &non_function);
+  __ bind(&non_smi);
+  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx);
+  __ j(equal, masm->isolate()->builtins()->CallFunction(),
+       RelocInfo::CODE_TARGET);
+  __ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE);
+  __ j(not_equal, &non_function);
+
+  // 1. Call to function proxy.
+  // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
+  __ movp(rdi, FieldOperand(rdi, JSFunctionProxy::kCallTrapOffset));
+  __ AssertNotSmi(rdi);
+  __ jmp(&non_smi);
+
+  // 2. Call to something else, which might have a [[Call]] internal method (if
+  // not we raise an exception).
+  __ bind(&non_function);
+  // TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
+  // be awesome instead; i.e. a trivial improvement would be to call into the
+  // runtime and just deal with the API function there instead of returning a
+  // delegate from a runtime call that just jumps back to the runtime once
+  // called. Or, bonus points, call directly into the C API function here, as
+  // we do in some Crankshaft fast cases.
+  StackArgumentsAccessor args(rsp, rax);
+  // Overwrite the original receiver with the (original) target.
+  __ movp(args.GetReceiverOperand(), rdi);
+  {
+    // Determine the delegate for the target (if any).
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    __ Integer32ToSmi(rax, rax);
+    __ Push(rax);
+    __ Push(rdi);
+    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
+    __ movp(rdi, rax);
+    __ Pop(rax);
+    __ SmiToInteger32(rax, rax);
+  }
+  // The delegate is always a regular function.
+  __ AssertFunction(rdi);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+}
+
+
 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
   // Lookup the function in the JavaScript frame.
   __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
   // Lookup the function in the JavaScript frame.
   __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
index 55891d51ef6014f8b26e6ea52f982a0109f7e10b..a814bfb59947228c6d02c3e422e97753da53fe15 100644 (file)
@@ -1902,36 +1902,10 @@ static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
 }
 
 
 }
 
 
-static void EmitSlowCase(Isolate* isolate,
-                         MacroAssembler* masm,
-                         StackArgumentsAccessor* args,
-                         int argc,
-                         Label* non_function) {
-  // Check for function proxy.
-  __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
-  __ j(not_equal, non_function);
-  __ PopReturnAddressTo(rcx);
-  __ Push(rdi);  // put proxy as additional argument under return address
-  __ PushReturnAddressFrom(rcx);
-  __ Set(rax, argc + 1);
-  __ Set(rbx, 0);
-  __ GetBuiltinEntry(rdx, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
-  {
-    Handle<Code> adaptor =
-        masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
-    __ jmp(adaptor, RelocInfo::CODE_TARGET);
-  }
-
-  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
-  // of the original receiver from the call site).
-  __ bind(non_function);
-  __ movp(args->GetReceiverOperand(), rdi);
+static void EmitSlowCase(MacroAssembler* masm, StackArgumentsAccessor* args,
+                         int argc) {
   __ Set(rax, argc);
   __ Set(rax, argc);
-  __ Set(rbx, 0);
-  __ GetBuiltinEntry(rdx, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
-  Handle<Code> adaptor =
-      isolate->builtins()->ArgumentsAdaptorTrampoline();
-  __ Jump(adaptor, RelocInfo::CODE_TARGET);
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -1956,13 +1930,12 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
   // rdi : the function to call
 
   // wrap_and_call can only be true if we are compiling a monomorphic method.
   // rdi : the function to call
 
   // wrap_and_call can only be true if we are compiling a monomorphic method.
-  Isolate* isolate = masm->isolate();
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
   StackArgumentsAccessor args(rsp, argc);
 
   if (needs_checks) {
     // Check that the function really is a JavaScript function.
   StackArgumentsAccessor args(rsp, argc);
 
   if (needs_checks) {
     // Check that the function really is a JavaScript function.
-    __ JumpIfSmi(rdi, &non_function);
+    __ JumpIfSmi(rdi, &slow);
 
     // Goto slow case if we do not have a function.
     __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
 
     // Goto slow case if we do not have a function.
     __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
@@ -1997,7 +1970,7 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ bind(&slow);
   if (needs_checks) {
     // Slow-case: Non-function called.
     __ bind(&slow);
-    EmitSlowCase(isolate, masm, &args, argc, &non_function);
+    EmitSlowCase(masm, &args, argc);
   }
 
   if (call_as_method) {
   }
 
   if (call_as_method) {
@@ -2113,32 +2086,28 @@ void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
   __ movp(rcx, FieldOperand(rbx, rdx, times_pointer_size,
                             FixedArray::kHeaderSize));
   // Verify that ecx contains an AllocationSite
   __ movp(rcx, FieldOperand(rbx, rdx, times_pointer_size,
                             FixedArray::kHeaderSize));
   // Verify that ecx contains an AllocationSite
-  Factory* factory = masm->isolate()->factory();
-  __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset),
-         factory->allocation_site_map());
-  __ j(not_equal, &miss);
+  __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
+                 Heap::kAllocationSiteMapRootIndex);
+  __ j(not_equal, &miss, Label::kNear);
 
   // Increment the call count for monomorphic function calls.
 
   // Increment the call count for monomorphic function calls.
-  __ SmiAddConstant(FieldOperand(rbx, rdx, times_pointer_size,
-                                 FixedArray::kHeaderSize + kPointerSize),
-                    Smi::FromInt(CallICNexus::kCallCountIncrement));
+  {
+    __ SmiAddConstant(FieldOperand(rbx, rdx, times_pointer_size,
+                                   FixedArray::kHeaderSize + kPointerSize),
+                      Smi::FromInt(CallICNexus::kCallCountIncrement));
 
 
-  __ movp(rbx, rcx);
-  __ movp(rdx, rdi);
-  ArrayConstructorStub stub(masm->isolate(), arg_count());
-  __ TailCallStub(&stub);
+    __ movp(rbx, rcx);
+    __ movp(rdx, rdi);
+    ArrayConstructorStub stub(masm->isolate(), arg_count());
+    __ TailCallStub(&stub);
+  }
 
   __ bind(&miss);
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
 
   __ bind(&miss);
   GenerateMiss(masm);
 
   // The slow case, we need this no matter what to complete a call after a miss.
-  CallFunctionNoFeedback(masm,
-                         arg_count(),
-                         true,
-                         CallAsMethod());
-
-  // Unreachable.
-  __ int3();
+  __ Set(rax, arg_count());
+  __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 }
 
 
 }
 
 
@@ -2152,7 +2121,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   const int generic_offset =
       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
-  Label slow, non_function, wrap, cont;
+  Label slow, wrap, cont;
   Label have_js_function;
   int argc = arg_count();
   StackArgumentsAccessor args(rsp, argc);
   Label have_js_function;
   int argc = arg_count();
   StackArgumentsAccessor args(rsp, argc);
@@ -2207,7 +2176,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   __ InvokeFunction(rdi, actual, JUMP_FUNCTION, NullCallWrapper());
 
   __ bind(&slow);
   __ InvokeFunction(rdi, actual, JUMP_FUNCTION, NullCallWrapper());
 
   __ bind(&slow);
-  EmitSlowCase(isolate, masm, &args, argc, &non_function);
+  EmitSlowCase(masm, &args, argc);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
 
   if (CallAsMethod()) {
     __ bind(&wrap);
@@ -2288,7 +2257,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   // the slow case
   __ bind(&slow_start);
   // Check that function is not a smi.
   // the slow case
   __ bind(&slow_start);
   // Check that function is not a smi.
-  __ JumpIfSmi(rdi, &non_function);
+  __ JumpIfSmi(rdi, &slow);
   // Check that function is a JSFunction.
   __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
   __ j(not_equal, &slow);
   // Check that function is a JSFunction.
   __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
   __ j(not_equal, &slow);
index c67d955a897e4dfc67623626f334f02f3b92f279..884cbab0efb62ad660e1fb749566406b2ff595f4 100644 (file)
@@ -3394,6 +3394,18 @@ void MacroAssembler::AssertName(Register object) {
 }
 
 
 }
 
 
+void MacroAssembler::AssertFunction(Register object) {
+  if (emit_debug_code()) {
+    testb(object, Immediate(kSmiTagMask));
+    Check(not_equal, kOperandIsASmiAndNotAFunction);
+    Push(object);
+    CmpObjectType(object, JS_FUNCTION_TYPE, object);
+    Pop(object);
+    Check(equal, kOperandIsNotAFunction);
+  }
+}
+
+
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
   if (emit_debug_code()) {
     Label done_checking;
 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
   if (emit_debug_code()) {
     Label done_checking;
@@ -4543,6 +4555,12 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
 }
 
 
 }
 
 
+void MacroAssembler::LoadGlobalProxy(Register dst) {
+  movp(dst, GlobalObjectOperand());
+  movp(dst, FieldOperand(dst, GlobalObject::kGlobalProxyOffset));
+}
+
+
 void MacroAssembler::LoadTransitionedArrayMapConditional(
     ElementsKind expected_kind,
     ElementsKind transitioned_kind,
 void MacroAssembler::LoadTransitionedArrayMapConditional(
     ElementsKind expected_kind,
     ElementsKind transitioned_kind,
index 63feb828407b11f8c39bfeda27bceeb898d5824a..cce88d8cc7f2b7ba25a8e064cc23508881c986e6 100644 (file)
@@ -148,6 +148,21 @@ class MacroAssembler: public Assembler {
   void CompareRoot(const Operand& with, Heap::RootListIndex index);
   void PushRoot(Heap::RootListIndex index);
 
   void CompareRoot(const Operand& with, Heap::RootListIndex index);
   void PushRoot(Heap::RootListIndex index);
 
+  // Compare the object in a register to a value and jump if they are equal.
+  void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal,
+                  Label::Distance if_equal_distance = Label::kNear) {
+    CompareRoot(with, index);
+    j(equal, if_equal, if_equal_distance);
+  }
+
+  // Compare the object in a register to a value and jump if they are not equal.
+  void JumpIfNotRoot(Register with, Heap::RootListIndex index,
+                     Label* if_not_equal,
+                     Label::Distance if_not_equal_distance = Label::kNear) {
+    CompareRoot(with, index);
+    j(not_equal, if_not_equal, if_not_equal_distance);
+  }
+
   // These functions do not arrange the registers in any particular order so
   // they are not useful for calls that can cause a GC.  The caller can
   // exclude up to 3 registers that do not need to be saved and restored.
   // These functions do not arrange the registers in any particular order so
   // they are not useful for calls that can cause a GC.  The caller can
   // exclude up to 3 registers that do not need to be saved and restored.
@@ -1101,6 +1116,9 @@ class MacroAssembler: public Assembler {
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
+  // Abort execution if argument is not a JSFunction, enabled via --debug-code.
+  void AssertFunction(Register object);
+
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object);
   // Abort execution if argument is not undefined or an AllocationSite, enabled
   // via --debug-code.
   void AssertUndefinedOrAllocationSite(Register object);
@@ -1253,6 +1271,9 @@ class MacroAssembler: public Assembler {
   // Find the function context up the context chain.
   void LoadContext(Register dst, int context_chain_length);
 
   // Find the function context up the context chain.
   void LoadContext(Register dst, int context_chain_length);
 
+  // Load the global proxy from the current context.
+  void LoadGlobalProxy(Register dst);
+
   // Conditionally load the cached Array transitioned map of type
   // transitioned_kind from the native context if the map in register
   // map_in_out is the cached Array map in the native context of
   // Conditionally load the cached Array transitioned map of type
   // transitioned_kind from the native context if the map in register
   // map_in_out is the cached Array map in the native context of