PPC: [builtin] Refactor Invoke to deal with any kind of callable.
authormbrandy <mbrandy@us.ibm.com>
Wed, 30 Sep 2015 16:28:41 +0000 (09:28 -0700)
committerJongsoo Yoon <join.yoon@samsung.com>
Fri, 20 Nov 2015 13:32:15 +0000 (22:32 +0900)
Port 634d1d86d8e98584097c6cb548a68ecf705c44f7

Original commit message:
    Now both Execution::Call and Execution::New can deal with any
    kind of target and will raise a proper exception if the target is not
    callable (which is not yet spec compliant for New, as we would
    have to check IsConstructor instead, which we don't have yet).

    Now we no longer need to do any of these weird call/construct
    delegate gymnastics in C++, and we finally have a single true
    bottleneck for Call/Construct abstract operations in the code
    base, with only a few special handlings left in the compilers to
    optimize the JSFunction case.

R=bmeurer@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com, dstence@us.ibm.com
BUG=v8:4430, v8:4413
LOG=n

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

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

src/ppc/builtins-ppc.cc

index 83d81256f6678d740a8451c97c92c2da58e61846..77f3aa250d519a812be07854f5e48ef9d523d848 100644 (file)
@@ -1605,13 +1605,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
   //  -- r4 : the target to call (can be any Object).
   // -----------------------------------
 
-  Label non_smi, non_function;
-  __ JumpIfSmi(r4, &non_function);
+  Label non_callable, non_function, non_smi;
+  __ JumpIfSmi(r4, &non_callable);
   __ bind(&non_smi);
-  __ CompareObjectType(r4, r5, r5, JS_FUNCTION_TYPE);
+  __ CompareObjectType(r4, r7, r8, JS_FUNCTION_TYPE);
   __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
           eq);
-  __ cmpi(r5, Operand(JS_FUNCTION_PROXY_TYPE));
+  __ cmpi(r8, Operand(JS_FUNCTION_PROXY_TYPE));
   __ bne(&non_function);
 
   // 1. Call to function proxy.
@@ -1623,28 +1623,24 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
   // 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.
-  __ ShiftLeftImm(r5, r3, Operand(kPointerSizeLog2));
-  __ StorePX(r4, MemOperand(sp, r5));
+  // Check if target has a [[Call]] internal method.
+  __ lbz(r7, FieldMemOperand(r7, Map::kBitFieldOffset));
+  __ TestBit(r7, Map::kIsCallable, r0);
+  __ beq(&non_callable, cr0);
+  // Overwrite the original receiver the (original) target.
+  __ ShiftLeftImm(r8, r3, Operand(kPointerSizeLog2));
+  __ StorePX(r4, MemOperand(sp, r8));
+  // Let the "call_as_function_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, r4);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+
+  // 3. Call to something that is not callable.
+  __ bind(&non_callable);
   {
-    // Determine the delegate for the target (if any).
     FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
-    __ SmiTag(r3);
-    __ Push(r3, r4);
-    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
-    __ mr(r4, r3);
-    __ Pop(r3);
-    __ SmiUntag(r3);
+    __ Push(r4);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(r4);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
@@ -1680,32 +1676,41 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
   //          the JSFunction on which new was invoked initially)
   // -----------------------------------
 
-  Label slow;
-  __ JumpIfSmi(r4, &slow);
-  __ CompareObjectType(r4, r8, r8, JS_FUNCTION_TYPE);
+  Label non_callable, non_function;
+  __ JumpIfSmi(r4, &non_callable);
+  __ CompareObjectType(r4, r7, r8, JS_FUNCTION_TYPE);
   __ Jump(masm->isolate()->builtins()->ConstructFunction(),
           RelocInfo::CODE_TARGET, eq);
   __ cmpi(r8, Operand(JS_FUNCTION_PROXY_TYPE));
-  __ bne(&slow);
+  __ bne(&non_function);
 
+  // 1. Construct of function proxy.
   // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
   __ LoadP(r4, FieldMemOperand(r4, JSFunctionProxy::kConstructTrapOffset));
   __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 
-  __ bind(&slow);
+  // 2. Construct of something that else, which might have a [[Construct]]
+  // internal method (if not we raise an exception).
+  __ bind(&non_function);
+  // Check if target has a [[Call]] internal method.
+  // TODO(bmeurer): This shoud use IsConstructor once available.
+  __ lbz(r7, FieldMemOperand(r7, Map::kBitFieldOffset));
+  __ TestBit(r7, Map::kIsCallable, r0);
+  __ beq(&non_callable, cr0);
+  // Overwrite the original receiver the (original) target.
+  __ ShiftLeftImm(r8, r3, Operand(kPointerSizeLog2));
+  __ StorePX(r4, MemOperand(sp, r8));
+  // Let the "call_as_constructor_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, r4);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+
+  // 3. Construct of something that is not callable.
+  __ bind(&non_callable);
   {
-    // Determine the delegate for the target (if any).
     FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
-    __ SmiTag(r3);
-    __ Push(r3, r4);
-    __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
-    __ mr(r4, r3);
-    __ Pop(r3);
-    __ SmiUntag(r3);
+    __ Push(r4);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(r4);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }