[builtin] Refactor Invoke to deal with any kind of callable.
authorbmeurer <bmeurer@chromium.org>
Wed, 23 Sep 2015 05:43:57 +0000 (22:43 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 23 Sep 2015 05:44:08 +0000 (05:44 +0000)
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=jarin@chromium.org
BUG=v8:4430, v8:4413
LOG=n

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

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

15 files changed:
src/api.cc
src/arm/builtins-arm.cc
src/arm64/builtins-arm64.cc
src/arm64/simulator-arm64.cc
src/arm64/simulator-arm64.h
src/execution.cc
src/execution.h
src/ia32/builtins-ia32.cc
src/mips/builtins-mips.cc
src/mips64/builtins-mips64.cc
src/runtime/runtime-classes.cc
src/runtime/runtime-function.cc
src/runtime/runtime-internal.cc
src/runtime/runtime.h
src/x64/builtins-x64.cc

index 62e50dd..1cb00f2 100644 (file)
@@ -4244,18 +4244,9 @@ MaybeLocal<Value> Object::CallAsFunction(Local<Context> context,
   auto recv_obj = Utils::OpenHandle(*recv);
   STATIC_ASSERT(sizeof(v8::Local<v8::Value>) == sizeof(i::Object**));
   i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
-  i::Handle<i::JSFunction> fun;
-  if (self->IsJSFunction()) {
-    fun = i::Handle<i::JSFunction>::cast(self);
-  } else {
-    has_pending_exception =
-        !i::Execution::GetFunctionDelegate(isolate, self).ToHandle(&fun);
-    RETURN_ON_FAILED_EXECUTION(Value);
-    recv_obj = self;
-  }
   Local<Value> result;
   has_pending_exception = !ToLocal<Value>(
-      i::Execution::Call(isolate, fun, recv_obj, argc, args), &result);
+      i::Execution::Call(isolate, self, recv_obj, argc, args), &result);
   RETURN_ON_FAILED_EXECUTION(Value);
   RETURN_ESCAPED(result);
 }
@@ -4278,21 +4269,9 @@ MaybeLocal<Value> Object::CallAsConstructor(Local<Context> context, int argc,
   auto self = Utils::OpenHandle(this);
   STATIC_ASSERT(sizeof(v8::Local<v8::Value>) == sizeof(i::Object**));
   i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
-  if (self->IsJSFunction()) {
-    auto fun = i::Handle<i::JSFunction>::cast(self);
-    Local<Value> result;
-    has_pending_exception =
-        !ToLocal<Value>(i::Execution::New(fun, argc, args), &result);
-    RETURN_ON_FAILED_EXECUTION(Value);
-    RETURN_ESCAPED(result);
-  }
-  i::Handle<i::JSFunction> fun;
-  has_pending_exception =
-      !i::Execution::GetConstructorDelegate(isolate, self).ToHandle(&fun);
-  RETURN_ON_FAILED_EXECUTION(Value);
   Local<Value> result;
   has_pending_exception = !ToLocal<Value>(
-      i::Execution::Call(isolate, fun, self, argc, args), &result);
+      i::Execution::New(isolate, self, self, argc, args), &result);
   RETURN_ON_FAILED_EXECUTION(Value);
   RETURN_ESCAPED(result);
 }
index 9b87243..715118c 100644 (file)
@@ -1585,13 +1585,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
   //  -- r1 : the target to call (can be any Object).
   // -----------------------------------
 
-  Label non_smi, non_function;
-  __ JumpIfSmi(r1, &non_function);
+  Label non_callable, non_function, non_smi;
+  __ JumpIfSmi(r1, &non_callable);
   __ bind(&non_smi);
-  __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
+  __ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
   __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
           eq);
-  __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE));
+  __ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE));
   __ b(ne, &non_function);
 
   // 1. Call to function proxy.
@@ -1603,27 +1603,23 @@ 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.
+  // Check if target has a [[Call]] internal method.
+  __ ldrb(r4, FieldMemOperand(r4, Map::kBitFieldOffset));
+  __ tst(r4, Operand(1 << Map::kIsCallable));
+  __ b(eq, &non_callable);
+  // Overwrite the original receiver the (original) target.
   __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
+  // Let the "call_as_function_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, r1);
+  __ 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(r0);
-    __ Push(r0, r1);
-    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
-    __ mov(r1, r0);
-    __ Pop(r0);
-    __ SmiUntag(r0);
+    __ Push(r1);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(r1);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
@@ -1658,32 +1654,40 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
   //          the JSFunction on which new was invoked initially)
   // -----------------------------------
 
-  Label slow;
-  __ JumpIfSmi(r1, &slow);
-  __ CompareObjectType(r1, r5, r5, JS_FUNCTION_TYPE);
+  Label non_callable, non_function;
+  __ JumpIfSmi(r1, &non_callable);
+  __ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
   __ Jump(masm->isolate()->builtins()->ConstructFunction(),
           RelocInfo::CODE_TARGET, eq);
   __ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE));
-  __ b(ne, &slow);
+  __ b(ne, &non_function);
 
+  // 1. Construct of function proxy.
   // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
   __ ldr(r1, FieldMemOperand(r1, 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.
+  __ ldrb(r4, FieldMemOperand(r4, Map::kBitFieldOffset));
+  __ tst(r4, Operand(1 << Map::kIsCallable));
+  __ b(eq, &non_callable);
+  // Overwrite the original receiver the (original) target.
+  __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
+  // Let the "call_as_constructor_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, r1);
+  __ 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(r0);
-    __ Push(r0, r1);
-    __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
-    __ mov(r1, r0);
-    __ Pop(r0);
-    __ SmiUntag(r0);
+    __ Push(r1);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(r1);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
index 7a21635..53cf0ec 100644 (file)
@@ -1647,14 +1647,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
   //  -- x1 : the target to call (can be any Object).
   // -----------------------------------
 
-  Label non_smi, non_jsfunction, non_function;
-  __ JumpIfSmi(x1, &non_function);
+  Label non_callable, non_function, non_smi;
+  __ JumpIfSmi(x1, &non_callable);
   __ 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);
+  __ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
+  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
+          eq);
+  __ Cmp(x5, JS_FUNCTION_PROXY_TYPE);
   __ B(ne, &non_function);
 
   // 1. Call to function proxy.
@@ -1666,27 +1665,22 @@ 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.
+  // Check if target has a [[Call]] internal method.
+  __ Ldrb(x4, FieldMemOperand(x4, Map::kBitFieldOffset));
+  __ TestAndBranchIfAllClear(x4, 1 << Map::kIsCallable, &non_callable);
   // Overwrite the original receiver with the (original) target.
   __ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
+  // Let the "call_as_function_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, x1);
+  __ 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).
     FrameScope scope(masm, StackFrame::INTERNAL);
-    __ SmiTag(x0);
-    __ Push(x0, x1);
-    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
-    __ Mov(x1, x0);
-    __ Pop(x0);
-    __ SmiUntag(x0);
+    __ Push(x1);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(x1);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
@@ -1722,32 +1716,39 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
   //          the JSFunction on which new was invoked initially)
   // -----------------------------------
 
-  Label slow;
-  __ JumpIfSmi(x1, &slow);
-  __ CompareObjectType(x1, x5, x5, JS_FUNCTION_TYPE);
+  Label non_callable, non_function;
+  __ JumpIfSmi(x1, &non_callable);
+  __ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
   __ Jump(masm->isolate()->builtins()->ConstructFunction(),
           RelocInfo::CODE_TARGET, eq);
-  __ Cmp(x5, Operand(JS_FUNCTION_PROXY_TYPE));
-  __ B(ne, &slow);
+  __ Cmp(x5, JS_FUNCTION_PROXY_TYPE);
+  __ B(ne, &non_function);
 
+  // 1. Construct of function proxy.
   // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
   __ Ldr(x1, FieldMemOperand(x1, 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.
+  __ Ldrb(x4, FieldMemOperand(x4, Map::kBitFieldOffset));
+  __ TestAndBranchIfAllClear(x4, 1 << Map::kIsCallable, &non_callable);
+  // Overwrite the original receiver with the (original) target.
+  __ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
+  // Let the "call_as_constructor_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, x1);
+  __ 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).
     FrameScope scope(masm, StackFrame::INTERNAL);
-    __ SmiTag(x0);
-    __ Push(x0, x1);
-    __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
-    __ Mov(x1, x0);
-    __ Pop(x0);
-    __ SmiUntag(x0);
+    __ Push(x1);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(x1);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
index f4e4839..4e6a9d9 100644 (file)
@@ -178,13 +178,13 @@ double Simulator::CallDouble(byte* entry, CallArgument* args) {
 
 int64_t Simulator::CallJS(byte* entry,
                           Object* new_target,
-                          JSFunction* func,
+                          Object* target,
                           Object* revc,
                           int64_t argc,
                           Object*** argv) {
   CallArgument args[] = {
     CallArgument(new_target),
-    CallArgument(func),
+    CallArgument(target),
     CallArgument(revc),
     CallArgument(argc),
     CallArgument(argv),
@@ -193,6 +193,7 @@ int64_t Simulator::CallJS(byte* entry,
   return CallInt64(entry, args);
 }
 
+
 int64_t Simulator::CallRegExp(byte* entry,
                               String* input,
                               int64_t start_offset,
index cd734ad..e4d9a81 100644 (file)
@@ -188,7 +188,7 @@ class Simulator : public DecoderVisitor {
   // which set up the simulator state and grab the result on return.
   int64_t CallJS(byte* entry,
                  Object* new_target,
-                 JSFunction* func,
+                 Object* target,
                  Object* revc,
                  int64_t argc,
                  Object*** argv);
index c214e7c..9330de0 100644 (file)
@@ -9,8 +9,6 @@
 #include "src/deoptimizer.h"
 #include "src/isolate-inl.h"
 #include "src/messages.h"
-#include "src/parser.h"
-#include "src/prettyprinter.h"
 #include "src/vm-state-inl.h"
 
 namespace v8 {
@@ -55,47 +53,12 @@ static void PrintDeserializedCodeInfo(Handle<JSFunction> function) {
 
 namespace {
 
-MUST_USE_RESULT MaybeHandle<Object> Invoke(bool is_construct,
-                                           Handle<JSFunction> function,
+MUST_USE_RESULT MaybeHandle<Object> Invoke(Isolate* isolate, bool is_construct,
+                                           Handle<Object> target,
                                            Handle<Object> receiver, int argc,
                                            Handle<Object> args[],
                                            Handle<Object> new_target) {
-  Isolate* const isolate = function->GetIsolate();
-
-  // Convert calls on global objects to be calls on the global
-  // receiver instead to avoid having a 'this' pointer which refers
-  // directly to a global object.
-  if (receiver->IsGlobalObject()) {
-    receiver =
-        handle(Handle<GlobalObject>::cast(receiver)->global_proxy(), isolate);
-  }
-
-  // api callbacks can be called directly.
-  if (!is_construct && function->shared()->IsApiFunction()) {
-    SaveContext save(isolate);
-    isolate->set_context(function->context());
-    // Do proper receiver conversion for non-strict mode api functions.
-    if (!receiver->IsJSReceiver() &&
-        is_sloppy(function->shared()->language_mode())) {
-      if (receiver->IsUndefined() || receiver->IsNull()) {
-        receiver = handle(function->global_proxy(), isolate);
-      } else {
-        ASSIGN_RETURN_ON_EXCEPTION(
-            isolate, receiver, Execution::ToObject(isolate, receiver), Object);
-      }
-    }
-    DCHECK(function->context()->global_object()->IsGlobalObject());
-    auto value = Builtins::InvokeApiFunction(function, receiver, argc, args);
-    bool has_exception = value.is_null();
-    DCHECK(has_exception == isolate->has_pending_exception());
-    if (has_exception) {
-      isolate->ReportPendingMessages();
-      return MaybeHandle<Object>();
-    } else {
-      isolate->clear_pending_message();
-    }
-    return value;
-  }
+  DCHECK(!receiver->IsGlobalObject());
 
   // Entering JavaScript.
   VMState<JS> state(isolate);
@@ -109,7 +72,7 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(bool is_construct,
   // Placeholder for return value.
   Object* value = NULL;
 
-  typedef Object* (*JSEntryFunction)(Object* new_target, Object* function,
+  typedef Object* (*JSEntryFunction)(Object* new_target, Object* target,
                                      Object* receiver, int argc,
                                      Object*** args);
 
@@ -117,10 +80,6 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(bool is_construct,
       ? isolate->factory()->js_construct_entry_code()
       : isolate->factory()->js_entry_code();
 
-  // Make sure that the global object of the context we're about to
-  // make the current one is indeed a global object.
-  DCHECK(function->context()->global_object()->IsGlobalObject());
-
   {
     // Save and restore context around invocation and block the
     // allocation of handles without explicit handle scopes.
@@ -130,10 +89,12 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(bool is_construct,
 
     // Call the function through the right JS entry stub.
     Object* orig_func = *new_target;
-    JSFunction* func = *function;
+    Object* func = *target;
     Object* recv = *receiver;
     Object*** argv = reinterpret_cast<Object***>(args);
-    if (FLAG_profile_deserialization) PrintDeserializedCodeInfo(function);
+    if (FLAG_profile_deserialization && target->IsJSFunction()) {
+      PrintDeserializedCodeInfo(Handle<JSFunction>::cast(target));
+    }
     value = CALL_GENERATED_CODE(stub_entry, orig_func, func, recv, argc, argv);
   }
 
@@ -163,30 +124,64 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(bool is_construct,
 }  // namespace
 
 
+// static
 MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
                                     Handle<Object> receiver, int argc,
                                     Handle<Object> argv[]) {
-  if (!callable->IsJSFunction()) {
-    ASSIGN_RETURN_ON_EXCEPTION(isolate, callable,
-                               GetFunctionDelegate(isolate, callable), Object);
+  // Convert calls on global objects to be calls on the global
+  // receiver instead to avoid having a 'this' pointer which refers
+  // directly to a global object.
+  if (receiver->IsGlobalObject()) {
+    receiver =
+        handle(Handle<GlobalObject>::cast(receiver)->global_proxy(), isolate);
+  }
+
+  // api callbacks can be called directly.
+  if (callable->IsJSFunction() &&
+      Handle<JSFunction>::cast(callable)->shared()->IsApiFunction()) {
+    Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
+    SaveContext save(isolate);
+    isolate->set_context(function->context());
+    // Do proper receiver conversion for non-strict mode api functions.
+    if (!receiver->IsJSReceiver() &&
+        is_sloppy(function->shared()->language_mode())) {
+      if (receiver->IsUndefined() || receiver->IsNull()) {
+        receiver = handle(function->global_proxy(), isolate);
+      } else {
+        ASSIGN_RETURN_ON_EXCEPTION(
+            isolate, receiver, Execution::ToObject(isolate, receiver), Object);
+      }
+    }
+    DCHECK(function->context()->global_object()->IsGlobalObject());
+    auto value = Builtins::InvokeApiFunction(function, receiver, argc, argv);
+    bool has_exception = value.is_null();
+    DCHECK(has_exception == isolate->has_pending_exception());
+    if (has_exception) {
+      isolate->ReportPendingMessages();
+      return MaybeHandle<Object>();
+    } else {
+      isolate->clear_pending_message();
+    }
+    return value;
   }
-  Handle<JSFunction> func = Handle<JSFunction>::cast(callable);
-  return Invoke(false, func, receiver, argc, argv,
+  return Invoke(isolate, false, callable, receiver, argc, argv,
                 isolate->factory()->undefined_value());
 }
 
 
+// static
 MaybeHandle<Object> Execution::New(Handle<JSFunction> constructor, int argc,
                                    Handle<Object> argv[]) {
-  return New(constructor, constructor, argc, argv);
+  return New(constructor->GetIsolate(), constructor, constructor, argc, argv);
 }
 
 
-MaybeHandle<Object> Execution::New(Handle<JSFunction> constructor,
-                                   Handle<JSFunction> new_target, int argc,
+// static
+MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
+                                   Handle<Object> new_target, int argc,
                                    Handle<Object> argv[]) {
-  return Invoke(true, constructor, handle(constructor->global_proxy()), argc,
-                argv, new_target);
+  return Invoke(isolate, true, constructor,
+                isolate->factory()->undefined_value(), argc, argv, new_target);
 }
 
 
@@ -234,98 +229,6 @@ MaybeHandle<Object> Execution::TryCall(Handle<JSFunction> func,
 }
 
 
-// static
-MaybeHandle<JSFunction> Execution::GetFunctionDelegate(Isolate* isolate,
-                                                       Handle<Object> object) {
-  DCHECK(!object->IsJSFunction());
-  if (object->IsHeapObject()) {
-    DisallowHeapAllocation no_gc;
-
-    // If object is a function proxy, get its handler. Iterate if necessary.
-    Object* fun = *object;
-    while (fun->IsJSFunctionProxy()) {
-      fun = JSFunctionProxy::cast(fun)->call_trap();
-    }
-    if (fun->IsJSFunction()) {
-      return handle(JSFunction::cast(fun), isolate);
-    }
-
-    // We can also have exotic objects with [[Call]] internal methods.
-    if (fun->IsCallable()) {
-      return handle(isolate->native_context()->call_as_function_delegate(),
-                    isolate);
-    }
-  }
-
-  // If the Object doesn't have an instance-call handler we should
-  // throw a non-callable exception.
-  Handle<String> callsite = RenderCallSite(isolate, object);
-  THROW_NEW_ERROR(isolate,
-                  NewTypeError(MessageTemplate::kCalledNonCallable, callsite),
-                  JSFunction);
-}
-
-
-// static
-MaybeHandle<JSFunction> Execution::GetConstructorDelegate(
-    Isolate* isolate, Handle<Object> object) {
-  // If you return a function from here, it will be called when an
-  // attempt is made to call the given object as a constructor.
-
-  DCHECK(!object->IsJSFunction());
-  if (object->IsHeapObject()) {
-    DisallowHeapAllocation no_gc;
-
-    // If object is a function proxies, get its handler. Iterate if necessary.
-    Object* fun = *object;
-    while (fun->IsJSFunctionProxy()) {
-      // TODO(bmeurer): This should work based on [[Construct]]; our proxies
-      // are screwed.
-      fun = JSFunctionProxy::cast(fun)->call_trap();
-    }
-    if (fun->IsJSFunction()) {
-      return handle(JSFunction::cast(fun), isolate);
-    }
-
-    // We can also have exotic objects with [[Construct]] internal methods.
-    // TODO(bmeurer): This should use IsConstructor() as dictacted by the spec.
-    if (fun->IsCallable()) {
-      return handle(isolate->native_context()->call_as_constructor_delegate(),
-                    isolate);
-    }
-  }
-
-  // If the Object doesn't have an instance-call handler we should
-  // throw a non-callable exception.
-  Handle<String> callsite = RenderCallSite(isolate, object);
-  THROW_NEW_ERROR(isolate,
-                  NewTypeError(MessageTemplate::kCalledNonCallable, callsite),
-                  JSFunction);
-}
-
-
-// static
-Handle<String> Execution::RenderCallSite(Isolate* isolate,
-                                         Handle<Object> object) {
-  MessageLocation location;
-  if (isolate->ComputeLocation(&location)) {
-    Zone zone;
-    base::SmartPointer<ParseInfo> info(
-        location.function()->shared()->is_function()
-            ? new ParseInfo(&zone, location.function())
-            : new ParseInfo(&zone, location.script()));
-    if (Parser::ParseStatic(info.get())) {
-      CallPrinter printer(isolate, &zone);
-      const char* string = printer.Print(info->literal(), location.start_pos());
-      return isolate->factory()->NewStringFromAsciiChecked(string);
-    } else {
-      isolate->clear_pending_exception();
-    }
-  }
-  return Object::TypeOf(isolate, object);
-}
-
-
 void StackGuard::SetStackLimit(uintptr_t limit) {
   ExecutionAccess access(isolate_);
   // If the current limits are special (e.g. due to a pending interrupt) then
index 5c25082..3822cbb 100644 (file)
@@ -35,8 +35,9 @@ class Execution final : public AllStatic {
   MUST_USE_RESULT static MaybeHandle<Object> New(Handle<JSFunction> constructor,
                                                  int argc,
                                                  Handle<Object> argv[]);
-  MUST_USE_RESULT static MaybeHandle<Object> New(Handle<JSFunction> constructor,
-                                                 Handle<JSFunction> new_target,
+  MUST_USE_RESULT static MaybeHandle<Object> New(Isolate* isolate,
+                                                 Handle<Object> constructor,
+                                                 Handle<Object> new_target,
                                                  int argc,
                                                  Handle<Object> argv[]);
 
@@ -88,20 +89,6 @@ class Execution final : public AllStatic {
                                           Handle<JSFunction> fun,
                                           Handle<Object> pos,
                                           Handle<Object> is_global);
-
-  // Get a function delegate for the given non-function object.
-  // Used for support calling objects as functions.
-  MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionDelegate(
-      Isolate* isolate, Handle<Object> object);
-
-  // Get a function delegate (or undefined) for the given non-function
-  // object. Used for support calling objects as constructors.
-  MUST_USE_RESULT static MaybeHandle<JSFunction> GetConstructorDelegate(
-      Isolate* isolate, Handle<Object> object);
-
- private:
-  MUST_USE_RESULT static Handle<String> RenderCallSite(Isolate* isolate,
-                                                       Handle<Object> object);
 };
 
 
index a6d29cc..817b425 100644 (file)
@@ -1516,13 +1516,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
   //  -- edi : the target to call (can be any Object).
   // -----------------------------------
 
-  Label non_smi, non_function;
-  __ JumpIfSmi(edi, &non_function);
+  Label non_callable, non_function, non_smi;
+  __ JumpIfSmi(edi, &non_callable);
   __ bind(&non_smi);
-  __ CmpObjectType(edi, JS_FUNCTION_TYPE, edx);
+  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
   __ j(equal, masm->isolate()->builtins()->CallFunction(),
        RelocInfo::CODE_TARGET);
-  __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
+  __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
   __ j(not_equal, &non_function);
 
   // 1. Call to function proxy.
@@ -1534,28 +1534,22 @@ 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.
+  // Check if target has a [[Call]] internal method.
+  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
+  __ j(zero, &non_callable, Label::kNear);
   // Overwrite the original receiver with the (original) target.
   __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
+  // Let the "call_as_function_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
+  __ 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).
     FrameScope scope(masm, StackFrame::INTERNAL);
-    __ SmiTag(eax);
-    __ Push(eax);
     __ Push(edi);
-    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
-    __ mov(edi, eax);
-    __ Pop(eax);
-    __ SmiUntag(eax);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(edi);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
@@ -1591,33 +1585,39 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
   //  -- edi : the constructor to call (can be any Object)
   // -----------------------------------
 
-  Label slow;
-  __ JumpIfSmi(edi, &slow, Label::kNear);
+  Label non_callable, non_function;
+  __ JumpIfSmi(edi, &non_callable);
   __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
   __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
        RelocInfo::CODE_TARGET);
   __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
-  __ j(not_equal, &slow, Label::kNear);
+  __ j(not_equal, &non_function, Label::kNear);
 
+  // 1. Construct of function proxy.
   // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
   __ mov(edi, FieldOperand(edi, JSFunctionProxy::kConstructTrapOffset));
   __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 
-  __ bind(&slow);
+  // 2. Construct of something 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.
+  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
+  __ j(zero, &non_callable, Label::kNear);
+  // Overwrite the original receiver with the (original) target.
+  __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
+  // Let the "call_as_constructor_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
+  __ 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).
     FrameScope scope(masm, StackFrame::INTERNAL);
-    __ SmiTag(eax);
-    __ Push(eax);
     __ Push(edi);
-    __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
-    __ mov(edi, eax);
-    __ Pop(eax);
-    __ SmiUntag(eax);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(edi);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
index 912b860..939ef05 100644 (file)
@@ -1596,14 +1596,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
   //  -- a1 : the target to call (can be any Object).
   // -----------------------------------
 
-  Label non_smi, non_function;
-  __ JumpIfSmi(a1, &non_function);
+  Label non_callable, non_function, non_smi;
+  __ JumpIfSmi(a1, &non_callable);
   __ bind(&non_smi);
-  __ GetObjectType(a1, a2, a2);
+  __ GetObjectType(a1, t1, t2);
   __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
-          eq, a2, Operand(JS_FUNCTION_TYPE));
-  __ Branch(&non_function, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE));
-
+          eq, t2, Operand(JS_FUNCTION_TYPE));
+  __ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
 
   // 1. Call to function proxy.
   // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
@@ -1614,29 +1613,25 @@ 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.
+  // Check if target has a [[Call]] internal method.
+  __ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
+  __ And(t1, t1, Operand(1 << Map::kIsCallable));
+  __ Branch(&non_callable, eq, t1, Operand(zero_reg));
   // Overwrite the original receiver with the (original) target.
   __ sll(at, a0, kPointerSizeLog2);
   __ addu(at, sp, at);
   __ sw(a1, MemOperand(at));
+  // Let the "call_as_function_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, a1);
+  __ 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).
-    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.
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    __ Push(a1);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(a1);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
@@ -1672,31 +1667,41 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
   //          the JSFunction on which new was invoked initially)
   // -----------------------------------
 
-  Label slow;
-  __ JumpIfSmi(a1, &slow);
-  __ GetObjectType(a1, t1, t1);
+  Label non_callable, non_function;
+  __ JumpIfSmi(a1, &non_callable);
+  __ GetObjectType(a1, t1, t2);
   __ Jump(masm->isolate()->builtins()->ConstructFunction(),
-          RelocInfo::CODE_TARGET, eq, t1, Operand(JS_FUNCTION_TYPE));
-  __ Branch(&slow, ne, t1, Operand(JS_FUNCTION_PROXY_TYPE));
+          RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
+  __ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
 
+  // 1. Construct of function proxy.
   // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
   __ lw(a1, FieldMemOperand(a1, 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.
+  __ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
+  __ And(t1, t1, Operand(1 << Map::kIsCallable));
+  __ Branch(&non_callable, eq, t1, Operand(zero_reg));
+  // Overwrite the original receiver with the (original) target.
+  __ sll(at, a0, kPointerSizeLog2);
+  __ addu(at, sp, at);
+  __ sw(a1, MemOperand(at));
+  // Let the "call_as_constructor_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
+  __ 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).
-    FrameScope scope(masm, StackFrame::INTERNAL);
-    __ SmiTag(a0);
-    __ Push(a0, a1);
-    __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
-    __ mov(a1, v0);
-    __ Pop(a0);
-    __ SmiUntag(a0);
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    __ Push(a1);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(a1);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
index d23a0f1..b588f78 100644 (file)
@@ -1593,13 +1593,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
   //  -- a1 : the target to call (can be any Object).
   // -----------------------------------
 
-  Label non_smi, non_function;
-  __ JumpIfSmi(a1, &non_function);
+  Label non_callable, non_function, non_smi;
+  __ JumpIfSmi(a1, &non_callable);
   __ bind(&non_smi);
-  __ GetObjectType(a1, a2, a2);
+  __ GetObjectType(a1, t1, t2);
   __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
-          eq, a2, Operand(JS_FUNCTION_TYPE));
-  __ Branch(&non_function, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE));
+          eq, t2, Operand(JS_FUNCTION_TYPE));
+  __ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
 
   // 1. Call to function proxy.
   // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
@@ -1610,29 +1610,25 @@ 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.
+  // Check if target has a [[Call]] internal method.
+  __ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
+  __ And(t1, t1, Operand(1 << Map::kIsCallable));
+  __ Branch(&non_callable, eq, t1, Operand(zero_reg));
   // Overwrite the original receiver with the (original) target.
   __ dsll(at, a0, kPointerSizeLog2);
   __ daddu(at, sp, at);
   __ sd(a1, MemOperand(at));
+  // Let the "call_as_function_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, a1);
+  __ 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).
-    FrameScope scope(masm, StackFrame::INTERNAL);
-    __ SmiTag(a0);
-    __ Push(a0, a1);
-    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
-    __ mov(a1, v0);
-    __ Pop(a0);
-    __ SmiUntag(a0);
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    __ Push(a1);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(a1);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
@@ -1667,31 +1663,41 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
   //          the JSFunction on which new was invoked initially)
   // -----------------------------------
 
-  Label slow;
-  __ JumpIfSmi(a1, &slow);
-  __ GetObjectType(a1, a5, a5);
+  Label non_callable, non_function;
+  __ JumpIfSmi(a1, &non_callable);
+  __ GetObjectType(a1, t1, t2);
   __ Jump(masm->isolate()->builtins()->ConstructFunction(),
-          RelocInfo::CODE_TARGET, eq, a5, Operand(JS_FUNCTION_TYPE));
-  __ Branch(&slow, ne, a5, Operand(JS_FUNCTION_PROXY_TYPE));
+          RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
+  __ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
 
+  // 1. Construct of function proxy.
   // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
   __ ld(a1, FieldMemOperand(a1, 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.
+  __ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
+  __ And(t1, t1, Operand(1 << Map::kIsCallable));
+  __ Branch(&non_callable, eq, t1, Operand(zero_reg));
+  // Overwrite the original receiver with the (original) target.
+  __ dsll(at, a0, kPointerSizeLog2);
+  __ daddu(at, sp, at);
+  __ sd(a1, MemOperand(at));
+  // Let the "call_as_constructor_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
+  __ 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).
-    FrameScope scope(masm, StackFrame::INTERNAL);
-    __ SmiTag(a0);
-    __ Push(a0, a1);
-    __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
-    __ mov(a1, v0);
-    __ Pop(a0);
-    __ SmiUntag(a0);
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    __ Push(a1);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(a1);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
index 050da01..50c2cca 100644 (file)
@@ -520,8 +520,9 @@ RUNTIME_FUNCTION(Runtime_DefaultConstructorCallSuper) {
 
   Handle<Object> result;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, Execution::New(super_constructor, original_constructor,
-                                      argument_count, arguments.get()));
+      isolate, result,
+      Execution::New(isolate, super_constructor, original_constructor,
+                     argument_count, arguments.get()));
 
   return *result;
 }
index 6585b4f..5600166 100644 (file)
@@ -494,16 +494,9 @@ RUNTIME_FUNCTION(Runtime_NewObjectFromBound) {
         bound_args->get(JSFunction::kBoundArgumentsStartIndex + i), isolate);
   }
 
-  if (!bound_function->IsJSFunction()) {
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, bound_function,
-        Execution::GetConstructorDelegate(isolate, bound_function));
-  }
-  DCHECK(bound_function->IsJSFunction());
-
   Handle<Object> result;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, Execution::New(Handle<JSFunction>::cast(bound_function),
+      isolate, result, Execution::New(isolate, bound_function, bound_function,
                                       total_argc, param_data.get()));
   return *result;
 }
@@ -564,30 +557,6 @@ RUNTIME_FUNCTION(Runtime_Apply) {
 }
 
 
-RUNTIME_FUNCTION(Runtime_GetFunctionDelegate) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-  RUNTIME_ASSERT(!object->IsJSFunction());
-  Handle<JSFunction> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, Execution::GetFunctionDelegate(isolate, object));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-  RUNTIME_ASSERT(!object->IsJSFunction());
-  Handle<JSFunction> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, Execution::GetConstructorDelegate(isolate, object));
-  return *result;
-}
-
-
 RUNTIME_FUNCTION(Runtime_GetOriginalConstructor) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 0);
index 18b9481..90d5532 100644 (file)
@@ -11,6 +11,8 @@
 #include "src/frames-inl.h"
 #include "src/isolate-inl.h"
 #include "src/messages.h"
+#include "src/parser.h"
+#include "src/prettyprinter.h"
 
 namespace v8 {
 namespace internal {
@@ -409,5 +411,39 @@ RUNTIME_FUNCTION(Runtime_GetCodeStubExportsObject) {
   return isolate->heap()->code_stub_exports_object();
 }
 
+
+namespace {
+
+Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object) {
+  MessageLocation location;
+  if (isolate->ComputeLocation(&location)) {
+    Zone zone;
+    base::SmartPointer<ParseInfo> info(
+        location.function()->shared()->is_function()
+            ? new ParseInfo(&zone, location.function())
+            : new ParseInfo(&zone, location.script()));
+    if (Parser::ParseStatic(info.get())) {
+      CallPrinter printer(isolate, &zone);
+      const char* string = printer.Print(info->literal(), location.start_pos());
+      return isolate->factory()->NewStringFromAsciiChecked(string);
+    } else {
+      isolate->clear_pending_exception();
+    }
+  }
+  return Object::TypeOf(isolate, object);
+}
+
+}  // namespace
+
+
+RUNTIME_FUNCTION(Runtime_ThrowCalledNonCallable) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(1, args.length());
+  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+  Handle<String> callsite = RenderCallSite(isolate, object);
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate, NewTypeError(MessageTemplate::kCalledNonCallable, callsite));
+}
+
 }  // namespace internal
 }  // namespace v8
index c1f72bb..b22a36f 100644 (file)
@@ -244,8 +244,6 @@ namespace internal {
   F(NewObjectFromBound, 1, 1)                               \
   F(Call, -1 /* >= 2 */, 1)                                 \
   F(Apply, 5, 1)                                            \
-  F(GetFunctionDelegate, 1, 1)                              \
-  F(GetConstructorDelegate, 1, 1)                           \
   F(GetOriginalConstructor, 0, 1)                           \
   F(CallFunction, -1 /* receiver + n args + function */, 1) \
   F(IsConstructCall, 0, 1)                                  \
@@ -341,7 +339,8 @@ namespace internal {
   F(HarmonyToString, 0, 1)                    \
   F(GetTypeFeedbackVector, 1, 1)              \
   F(GetCallerJSFunction, 0, 1)                \
-  F(GetCodeStubExportsObject, 0, 1)
+  F(GetCodeStubExportsObject, 0, 1)           \
+  F(ThrowCalledNonCallable, 1, 1)
 
 
 #define FOR_EACH_INTRINSIC_JSON(F) \
index e8cc438..41c224f 100644 (file)
@@ -1717,14 +1717,15 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
   //  -- rax : the number of arguments (not including the receiver)
   //  -- rdi : the target to call (can be any Object)
   // -----------------------------------
+  StackArgumentsAccessor args(rsp, rax);
 
-  Label non_smi, non_function;
-  __ JumpIfSmi(rdi, &non_function);
+  Label non_callable, non_function, non_smi;
+  __ JumpIfSmi(rdi, &non_callable);
   __ bind(&non_smi);
-  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx);
+  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
   __ j(equal, masm->isolate()->builtins()->CallFunction(),
        RelocInfo::CODE_TARGET);
-  __ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE);
+  __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
   __ j(not_equal, &non_function);
 
   // 1. Call to function proxy.
@@ -1736,29 +1737,23 @@ 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.
-  StackArgumentsAccessor args(rsp, rax);
+  // Check if target has a [[Call]] internal method.
+  __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
+           Immediate(1 << Map::kIsCallable));
+  __ j(zero, &non_callable, Label::kNear);
   // Overwrite the original receiver with the (original) target.
   __ movp(args.GetReceiverOperand(), rdi);
+  // Let the "call_as_function_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, rdi);
+  __ 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).
     FrameScope scope(masm, StackFrame::INTERNAL);
-    __ Integer32ToSmi(rax, rax);
-    __ Push(rax);
     __ Push(rdi);
-    __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
-    __ movp(rdi, rax);
-    __ Pop(rax);
-    __ SmiToInteger32(rax, rax);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(rdi);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }
 
 
@@ -1793,34 +1788,42 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
   //           the JSFunction on which new was invoked initially)
   //  -- rdi : the constructor to call (can be any Object)
   // -----------------------------------
+  StackArgumentsAccessor args(rsp, rax);
 
-  Label slow;
-  __ JumpIfSmi(rdi, &slow, Label::kNear);
+  Label non_callable, non_function;
+  __ JumpIfSmi(rdi, &non_callable);
   __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
   __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
        RelocInfo::CODE_TARGET);
   __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
-  __ j(not_equal, &slow, Label::kNear);
+  __ j(not_equal, &non_function, Label::kNear);
 
+  // 1. Construct of function proxy.
   // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
   __ movp(rdi, FieldOperand(rdi, JSFunctionProxy::kConstructTrapOffset));
   __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
 
-  __ bind(&slow);
+  // 2. Construct of something 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.
+  __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
+           Immediate(1 << Map::kIsCallable));
+  __ j(zero, &non_callable, Label::kNear);
+  // Overwrite the original receiver with the (original) target.
+  __ movp(args.GetReceiverOperand(), rdi);
+  // Let the "call_as_constructor_delegate" take care of the rest.
+  __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, rdi);
+  __ 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).
     FrameScope scope(masm, StackFrame::INTERNAL);
-    __ Integer32ToSmi(rax, rax);
-    __ Push(rax);
     __ Push(rdi);
-    __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
-    __ movp(rdi, rax);
-    __ Pop(rax);
-    __ SmiToInteger32(rax, rax);
+    __ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
   }
-  // The delegate is always a regular function.
-  __ AssertFunction(rdi);
-  __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
 }