[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}
This commit is contained in:
cbruni 2016-08-08 04:16:12 -07:00 committed by Commit bot
parent b12a51c1f6
commit b920d5f3ff
4 changed files with 43 additions and 32 deletions

View File

@ -157,16 +157,17 @@ class RelocatableArguments : public BuiltinArguments, public Relocatable {
} // namespace
MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
bool is_construct,
Handle<HeapObject> function,
Handle<Object> receiver,
int argc,
Handle<Object> args[]) {
int argc, Handle<Object> args[],
Handle<HeapObject> new_target) {
DCHECK(function->IsFunctionTemplateInfo() ||
(function->IsJSFunction() &&
JSFunction::cast(*function)->shared()->IsApiFunction()));
// Do proper receiver conversion for non-strict mode api functions.
if (!receiver->IsJSReceiver()) {
if (!is_construct && !receiver->IsJSReceiver()) {
if (function->IsFunctionTemplateInfo() ||
is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
@ -180,7 +181,6 @@ MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
? Handle<FunctionTemplateInfo>::cast(function)
: handle(JSFunction::cast(*function)->shared()->get_api_func_data(),
isolate);
Handle<HeapObject> new_target = isolate->factory()->undefined_value();
// Construct BuiltinArguments object:
// new target, function, arguments reversed, receiver.
const int kBufferSize = 32;
@ -204,8 +204,13 @@ MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
MaybeHandle<Object> result;
{
RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]);
result = HandleApiCallHelper<false>(isolate, function, new_target, fun_data,
receiver, arguments);
if (is_construct) {
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;
return result;

View File

@ -604,8 +604,9 @@ class Builtins {
bool is_initialized() const { return initialized_; }
MUST_USE_RESULT static MaybeHandle<Object> InvokeApiFunction(
Isolate* isolate, Handle<HeapObject> function, Handle<Object> receiver,
int argc, Handle<Object> args[]);
Isolate* isolate, bool is_construct, Handle<HeapObject> function,
Handle<Object> receiver, int argc, Handle<Object> args[],
Handle<HeapObject> new_target);
enum ExitFrameType { EXIT, BUILTIN_EXIT };

View File

@ -72,6 +72,30 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(Isolate* isolate, bool is_construct,
}
#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.
VMState<JS> state(isolate);
CHECK(AllowJavascriptExecution::IsAllowed(isolate));
@ -147,26 +171,6 @@ MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
receiver =
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,
isolate->factory()->undefined_value());
}

View File

@ -1344,8 +1344,8 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
if (getter->IsFunctionTemplateInfo()) {
return Builtins::InvokeApiFunction(
isolate, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
nullptr);
isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
nullptr, isolate->factory()->undefined_value());
} else if (getter->IsCallable()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here...
return Object::GetPropertyWithDefinedGetter(
@ -1427,8 +1427,9 @@ Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
Handle<Object> argv[] = {value};
RETURN_ON_EXCEPTION_VALUE(
isolate, Builtins::InvokeApiFunction(
isolate, Handle<FunctionTemplateInfo>::cast(setter),
receiver, arraysize(argv), argv),
isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
receiver, arraysize(argv), argv,
isolate->factory()->undefined_value()),
Nothing<bool>());
return Just(true);
} else if (setter->IsCallable()) {