Call directly to c callbacks in Invoke instead of transitioning to js and back out.
authordcarney <dcarney@chromium.org>
Thu, 22 Jan 2015 21:37:06 +0000 (13:37 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 22 Jan 2015 21:37:20 +0000 (21:37 +0000)
BUG=

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

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

src/builtins.cc
src/builtins.h
src/execution.cc

index 6fea014..20f8e84 100644 (file)
@@ -1062,11 +1062,8 @@ static inline Object* TypeCheck(Heap* heap, Object* recv,
 
 
 template <bool is_construct>
-MUST_USE_RESULT static Object* HandleApiCallHelper(
-    BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
-  DCHECK(is_construct == CalledAsConstructor(isolate));
-  Heap* heap = isolate->heap();
-
+MUST_USE_RESULT static MaybeHandle<Object> HandleApiCallHelper(
+    Isolate* isolate, BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
   HandleScope scope(isolate);
   Handle<JSFunction> function = args.called_function();
   // TODO(ishell): turn this back to a DCHECK.
@@ -1075,22 +1072,23 @@ MUST_USE_RESULT static Object* HandleApiCallHelper(
   Handle<FunctionTemplateInfo> fun_data(
       function->shared()->get_api_func_data(), isolate);
   if (is_construct) {
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+    ASSIGN_RETURN_ON_EXCEPTION(
         isolate, fun_data,
         isolate->factory()->ConfigureInstance(
-            fun_data, Handle<JSObject>::cast(args.receiver())));
+            fun_data, Handle<JSObject>::cast(args.receiver())),
+        Object);
   }
 
   DCHECK(!args[0]->IsNull());
   if (args[0]->IsUndefined()) args[0] = function->global_proxy();
 
-  Object* raw_holder = TypeCheck(heap, args[0], *fun_data);
+  Object* raw_holder = TypeCheck(isolate->heap(), args[0], *fun_data);
 
   if (raw_holder->IsNull()) {
     // This function cannot be called with the given receiver.  Abort!
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate,
-        NewTypeError("illegal_invocation", HandleVector(&function, 1)));
+    THROW_NEW_ERROR(
+        isolate, NewTypeError("illegal_invocation", HandleVector(&function, 1)),
+        Object);
   }
 
   Object* raw_call_data = fun_data->call_code();
@@ -1102,7 +1100,6 @@ MUST_USE_RESULT static Object* HandleApiCallHelper(
     v8::FunctionCallback callback =
         v8::ToCData<v8::FunctionCallback>(callback_obj);
     Object* data_obj = call_data->data();
-    Object* result;
 
     LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
     DCHECK(raw_holder->IsJSObject());
@@ -1116,28 +1113,73 @@ MUST_USE_RESULT static Object* HandleApiCallHelper(
                                      is_construct);
 
     v8::Handle<v8::Value> value = custom.Call(callback);
+    Handle<Object> result;
     if (value.IsEmpty()) {
-      result = heap->undefined_value();
+      result = isolate->factory()->undefined_value();
     } else {
-      result = *reinterpret_cast<Object**>(*value);
+      result = v8::Utils::OpenHandle(*value);
       result->VerifyApiCallResultType();
     }
 
-    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
-    if (!is_construct || result->IsJSObject()) return result;
+    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+    if (!is_construct || result->IsJSObject()) {
+      return scope.CloseAndEscape(result);
+    }
   }
 
-  return *args.receiver();
+  return scope.CloseAndEscape(args.receiver());
 }
 
 
 BUILTIN(HandleApiCall) {
-  return HandleApiCallHelper<false>(args, isolate);
+  HandleScope scope(isolate);
+  DCHECK(!CalledAsConstructor(isolate));
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     HandleApiCallHelper<false>(isolate, args));
+  return *result;
 }
 
 
 BUILTIN(HandleApiCallConstruct) {
-  return HandleApiCallHelper<true>(args, isolate);
+  HandleScope scope(isolate);
+  DCHECK(CalledAsConstructor(isolate));
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     HandleApiCallHelper<true>(isolate, args));
+  return *result;
+}
+
+
+MaybeHandle<Object> Builtins::InvokeApiFunction(Handle<JSFunction> function,
+                                                Handle<Object> receiver,
+                                                int argc,
+                                                Handle<Object> args[]) {
+  // Construct BuiltinArguments object: function, arguments reversed, receiver.
+  const int kBufferSize = 32;
+  Object* small_argv[kBufferSize];
+  Object** argv;
+  if (argc + 2 <= kBufferSize) {
+    argv = small_argv;
+  } else {
+    argv = new Object* [argc + 2];
+  }
+  argv[argc + 1] = *receiver;
+  for (int i = 0; i < argc; ++i) {
+    argv[argc - i] = *args[i];
+  }
+  argv[0] = *function;
+  MaybeHandle<Object> result;
+  {
+    auto isolate = function->GetIsolate();
+    BuiltinArguments<NEEDS_CALLED_FUNCTION> arguments(argc + 2,
+                                                      &argv[argc + 1]);
+    result = HandleApiCallHelper<false>(isolate, arguments);
+  }
+  if (argv != small_argv) {
+    delete[] argv;
+  }
+  return result;
 }
 
 
index 91f6741..8d09d57 100644 (file)
@@ -276,6 +276,10 @@ class Builtins {
 
   bool is_initialized() const { return initialized_; }
 
+  MUST_USE_RESULT static MaybeHandle<Object> InvokeApiFunction(
+      Handle<JSFunction> function, Handle<Object> receiver, int argc,
+      Handle<Object> args[]);
+
  private:
   Builtins();
 
index 998afb8..9f418ac 100644 (file)
@@ -58,6 +58,26 @@ MUST_USE_RESULT static MaybeHandle<Object> Invoke(
     Handle<Object> args[]) {
   Isolate* isolate = function->GetIsolate();
 
+  // api callbacks can be called directly.
+  if (!is_construct && function->shared()->IsApiFunction()) {
+    SaveContext save(isolate);
+    isolate->set_context(function->context());
+    if (receiver->IsGlobalObject()) {
+      receiver = handle(Handle<GlobalObject>::cast(receiver)->global_proxy());
+    }
+    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;
+  }
+
   // Entering JavaScript.
   VMState<JS> state(isolate);
   CHECK(AllowJavascriptExecution::IsAllowed(isolate));