Commit b920d5f3 authored by cbruni's avatar cbruni Committed by Commit bot

[api] Stay in C++ when constructing an API-function

This CL applies the same optimization already present for calling API-function.
Execution::New and Execution::Call now both check whether the target is an
API-function and avoid calling out into the construct/call stub.

BUG=chromium:630217

Review-Url: https://codereview.chromium.org/2203353002
Cr-Commit-Position: refs/heads/master@{#38433}
parent b12a51c1
...@@ -157,16 +157,17 @@ class RelocatableArguments : public BuiltinArguments, public Relocatable { ...@@ -157,16 +157,17 @@ class RelocatableArguments : public BuiltinArguments, public Relocatable {
} // namespace } // namespace
MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate, MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
bool is_construct,
Handle<HeapObject> function, Handle<HeapObject> function,
Handle<Object> receiver, Handle<Object> receiver,
int argc, int argc, Handle<Object> args[],
Handle<Object> args[]) { Handle<HeapObject> new_target) {
DCHECK(function->IsFunctionTemplateInfo() || DCHECK(function->IsFunctionTemplateInfo() ||
(function->IsJSFunction() && (function->IsJSFunction() &&
JSFunction::cast(*function)->shared()->IsApiFunction())); JSFunction::cast(*function)->shared()->IsApiFunction()));
// Do proper receiver conversion for non-strict mode api functions. // Do proper receiver conversion for non-strict mode api functions.
if (!receiver->IsJSReceiver()) { if (!is_construct && !receiver->IsJSReceiver()) {
if (function->IsFunctionTemplateInfo() || if (function->IsFunctionTemplateInfo() ||
is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) { is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver, ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
...@@ -180,7 +181,6 @@ MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate, ...@@ -180,7 +181,6 @@ MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
? Handle<FunctionTemplateInfo>::cast(function) ? Handle<FunctionTemplateInfo>::cast(function)
: handle(JSFunction::cast(*function)->shared()->get_api_func_data(), : handle(JSFunction::cast(*function)->shared()->get_api_func_data(),
isolate); isolate);
Handle<HeapObject> new_target = isolate->factory()->undefined_value();
// Construct BuiltinArguments object: // Construct BuiltinArguments object:
// new target, function, arguments reversed, receiver. // new target, function, arguments reversed, receiver.
const int kBufferSize = 32; const int kBufferSize = 32;
...@@ -204,8 +204,13 @@ MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate, ...@@ -204,8 +204,13 @@ MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
MaybeHandle<Object> result; MaybeHandle<Object> result;
{ {
RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]); RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]);
result = HandleApiCallHelper<false>(isolate, function, new_target, fun_data, if (is_construct) {
receiver, arguments); result = HandleApiCallHelper<true>(isolate, function, new_target,
fun_data, receiver, arguments);
} else {
result = HandleApiCallHelper<false>(isolate, function, new_target,
fun_data, receiver, arguments);
}
} }
if (argv != small_argv) delete[] argv; if (argv != small_argv) delete[] argv;
return result; return result;
......
...@@ -604,8 +604,9 @@ class Builtins { ...@@ -604,8 +604,9 @@ class Builtins {
bool is_initialized() const { return initialized_; } bool is_initialized() const { return initialized_; }
MUST_USE_RESULT static MaybeHandle<Object> InvokeApiFunction( MUST_USE_RESULT static MaybeHandle<Object> InvokeApiFunction(
Isolate* isolate, Handle<HeapObject> function, Handle<Object> receiver, Isolate* isolate, bool is_construct, Handle<HeapObject> function,
int argc, Handle<Object> args[]); Handle<Object> receiver, int argc, Handle<Object> args[],
Handle<HeapObject> new_target);
enum ExitFrameType { EXIT, BUILTIN_EXIT }; enum ExitFrameType { EXIT, BUILTIN_EXIT };
......
...@@ -72,6 +72,30 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(Isolate* isolate, bool is_construct, ...@@ -72,6 +72,30 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(Isolate* isolate, bool is_construct,
} }
#endif #endif
// api callbacks can be called directly.
if (target->IsJSFunction()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(target);
if ((!is_construct || function->IsConstructor()) &&
function->shared()->IsApiFunction()) {
SaveContext save(isolate);
isolate->set_context(function->context());
DCHECK(function->context()->global_object()->IsJSGlobalObject());
if (is_construct) receiver = isolate->factory()->the_hole_value();
auto value = Builtins::InvokeApiFunction(
isolate, is_construct, function, receiver, argc, args,
Handle<HeapObject>::cast(new_target));
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. // Entering JavaScript.
VMState<JS> state(isolate); VMState<JS> state(isolate);
CHECK(AllowJavascriptExecution::IsAllowed(isolate)); CHECK(AllowJavascriptExecution::IsAllowed(isolate));
...@@ -147,26 +171,6 @@ MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable, ...@@ -147,26 +171,6 @@ MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
receiver = receiver =
handle(Handle<JSGlobalObject>::cast(receiver)->global_proxy(), isolate); handle(Handle<JSGlobalObject>::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());
DCHECK(function->context()->global_object()->IsJSGlobalObject());
auto value =
Builtins::InvokeApiFunction(isolate, 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;
}
return Invoke(isolate, false, callable, receiver, argc, argv, return Invoke(isolate, false, callable, receiver, argc, argv,
isolate->factory()->undefined_value()); isolate->factory()->undefined_value());
} }
......
...@@ -1344,8 +1344,8 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) { ...@@ -1344,8 +1344,8 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate); Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
if (getter->IsFunctionTemplateInfo()) { if (getter->IsFunctionTemplateInfo()) {
return Builtins::InvokeApiFunction( return Builtins::InvokeApiFunction(
isolate, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0, isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
nullptr); nullptr, isolate->factory()->undefined_value());
} else if (getter->IsCallable()) { } else if (getter->IsCallable()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here... // TODO(rossberg): nicer would be to cast to some JSCallable here...
return Object::GetPropertyWithDefinedGetter( return Object::GetPropertyWithDefinedGetter(
...@@ -1427,8 +1427,9 @@ Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it, ...@@ -1427,8 +1427,9 @@ Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
Handle<Object> argv[] = {value}; Handle<Object> argv[] = {value};
RETURN_ON_EXCEPTION_VALUE( RETURN_ON_EXCEPTION_VALUE(
isolate, Builtins::InvokeApiFunction( isolate, Builtins::InvokeApiFunction(
isolate, Handle<FunctionTemplateInfo>::cast(setter), isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
receiver, arraysize(argv), argv), receiver, arraysize(argv), argv,
isolate->factory()->undefined_value()),
Nothing<bool>()); Nothing<bool>());
return Just(true); return Just(true);
} else if (setter->IsCallable()) { } else if (setter->IsCallable()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment