Commit ec61e6b4 authored by gsathya's avatar gsathya Committed by Commit bot

[promises] Remove one runtime call to create_resolving_functions

- Creates a new promise-utils.{h, cc} which refactors out the
logic to create resolving functions. This is shared between the
runtime functions and builtins.

- Changes PromiseResolveThenableJobInfo to store the context
since we no longer create the resolving functions in JS.

- Changes EnqueuPromiseResolveThenableJob to take in the promise and
  not the callbacks.

BUG=v8:5343

Review-Url: https://codereview.chromium.org/2487053002
Cr-Commit-Position: refs/heads/master@{#40941}
parent 3b49b457
...@@ -1570,6 +1570,8 @@ v8_source_set("v8_base") { ...@@ -1570,6 +1570,8 @@ v8_source_set("v8_base") {
"src/profiler/tracing-cpu-profiler.h", "src/profiler/tracing-cpu-profiler.h",
"src/profiler/unbound-queue-inl.h", "src/profiler/unbound-queue-inl.h",
"src/profiler/unbound-queue.h", "src/profiler/unbound-queue.h",
"src/promise-utils.cc",
"src/promise-utils.h",
"src/property-descriptor.cc", "src/property-descriptor.cc",
"src/property-descriptor.h", "src/property-descriptor.h",
"src/property-details.h", "src/property-details.h",
......
// Copyright 2016 the V8 project authors. All rights reserved. // Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "src/builtins/builtins-utils.h" #include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/promise-utils.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
enum PromiseResolvingFunctionContextSlot {
kAlreadyVisitedSlot = Context::MIN_CONTEXT_SLOTS,
kPromiseSlot,
kDebugEventSlot,
kPromiseContextLength,
};
// ES#sec-promise-resolve-functions // ES#sec-promise-resolve-functions
// Promise Resolve Functions // Promise Resolve Functions
BUILTIN(PromiseResolveClosure) { BUILTIN(PromiseResolveClosure) {
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<Context> context(isolate->context(), isolate); Handle<Context> context(isolate->context(), isolate);
Handle<Smi> already_visited(Smi::cast(context->get(kAlreadyVisitedSlot)),
isolate);
if (already_visited->value() != 0) { if (PromiseUtils::HasAlreadyVisited(context)) {
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
context->set(kAlreadyVisitedSlot, Smi::FromInt(1)); PromiseUtils::SetAlreadyVisited(context);
Handle<JSObject> promise(JSObject::cast(context->get(kPromiseSlot)), isolate); Handle<JSObject> promise = handle(PromiseUtils::GetPromise(context), isolate);
Handle<Object> value = args.atOrUndefined(isolate, 1); Handle<Object> value = args.atOrUndefined(isolate, 1);
MaybeHandle<Object> maybe_result; MaybeHandle<Object> maybe_result;
...@@ -46,18 +40,16 @@ BUILTIN(PromiseRejectClosure) { ...@@ -46,18 +40,16 @@ BUILTIN(PromiseRejectClosure) {
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<Context> context(isolate->context(), isolate); Handle<Context> context(isolate->context(), isolate);
Handle<Smi> already_visited(Smi::cast(context->get(kAlreadyVisitedSlot)),
isolate);
if (already_visited->value() != 0) { if (PromiseUtils::HasAlreadyVisited(context)) {
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
context->set(kAlreadyVisitedSlot, Smi::FromInt(1)); PromiseUtils::SetAlreadyVisited(context);
Handle<Object> value = args.atOrUndefined(isolate, 1); Handle<Object> value = args.atOrUndefined(isolate, 1);
Handle<JSObject> promise(JSObject::cast(context->get(kPromiseSlot)), isolate); Handle<JSObject> promise = handle(PromiseUtils::GetPromise(context), isolate);
Handle<Object> debug_event(context->get(kDebugEventSlot), isolate); Handle<Object> debug_event =
handle(PromiseUtils::GetDebugEvent(context), isolate);
MaybeHandle<Object> maybe_result; MaybeHandle<Object> maybe_result;
Handle<Object> argv[] = {promise, value, debug_event}; Handle<Object> argv[] = {promise, value, debug_event};
RETURN_FAILURE_ON_EXCEPTION( RETURN_FAILURE_ON_EXCEPTION(
...@@ -75,31 +67,10 @@ BUILTIN(CreateResolvingFunctions) { ...@@ -75,31 +67,10 @@ BUILTIN(CreateResolvingFunctions) {
Handle<JSObject> promise = args.at<JSObject>(1); Handle<JSObject> promise = args.at<JSObject>(1);
Handle<Object> debug_event = args.at<Object>(2); Handle<Object> debug_event = args.at<Object>(2);
Handle<JSFunction> resolve, reject;
Handle<Context> context = PromiseUtils::CreateResolvingFunctions(isolate, promise, debug_event,
isolate->factory()->NewPromiseResolvingFunctionContext( &resolve, &reject);
kPromiseContextLength);
context->set_native_context(*isolate->native_context());
context->set(kAlreadyVisitedSlot, Smi::kZero);
context->set(kPromiseSlot, *promise);
context->set(kDebugEventSlot, *debug_event);
Handle<SharedFunctionInfo> resolve_shared_fun(
isolate->native_context()->promise_resolve_shared_fun(), isolate);
Handle<JSFunction> resolve =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
isolate->sloppy_function_without_prototype_map(), resolve_shared_fun,
isolate->native_context(), TENURED);
Handle<SharedFunctionInfo> reject_shared_fun(
isolate->native_context()->promise_reject_shared_fun(), isolate);
Handle<JSFunction> reject =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
isolate->sloppy_function_without_prototype_map(), reject_shared_fun,
isolate->native_context(), TENURED);
resolve->set_context(*context);
reject->set_context(*context);
Handle<FixedArray> result = isolate->factory()->NewFixedArray(2); Handle<FixedArray> result = isolate->factory()->NewFixedArray(2);
result->set(0, *resolve); result->set(0, *resolve);
......
...@@ -981,7 +981,8 @@ Handle<Struct> Factory::NewStruct(InstanceType type) { ...@@ -981,7 +981,8 @@ Handle<Struct> Factory::NewStruct(InstanceType type) {
Handle<PromiseResolveThenableJobInfo> Factory::NewPromiseResolveThenableJobInfo( Handle<PromiseResolveThenableJobInfo> Factory::NewPromiseResolveThenableJobInfo(
Handle<JSReceiver> thenable, Handle<JSReceiver> then, Handle<JSReceiver> thenable, Handle<JSReceiver> then,
Handle<JSFunction> resolve, Handle<JSFunction> reject, Handle<JSFunction> resolve, Handle<JSFunction> reject,
Handle<Object> debug_id, Handle<Object> debug_name) { Handle<Object> debug_id, Handle<Object> debug_name,
Handle<Context> context) {
Handle<PromiseResolveThenableJobInfo> result = Handle<PromiseResolveThenableJobInfo> result =
Handle<PromiseResolveThenableJobInfo>::cast( Handle<PromiseResolveThenableJobInfo>::cast(
NewStruct(PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE)); NewStruct(PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE));
...@@ -991,6 +992,7 @@ Handle<PromiseResolveThenableJobInfo> Factory::NewPromiseResolveThenableJobInfo( ...@@ -991,6 +992,7 @@ Handle<PromiseResolveThenableJobInfo> Factory::NewPromiseResolveThenableJobInfo(
result->set_reject(*reject); result->set_reject(*reject);
result->set_debug_id(*debug_id); result->set_debug_id(*debug_id);
result->set_debug_name(*debug_name); result->set_debug_name(*debug_name);
result->set_context(*context);
return result; return result;
} }
......
...@@ -71,7 +71,8 @@ class V8_EXPORT_PRIVATE Factory final { ...@@ -71,7 +71,8 @@ class V8_EXPORT_PRIVATE Factory final {
Handle<PromiseResolveThenableJobInfo> NewPromiseResolveThenableJobInfo( Handle<PromiseResolveThenableJobInfo> NewPromiseResolveThenableJobInfo(
Handle<JSReceiver> thenable, Handle<JSReceiver> then, Handle<JSReceiver> thenable, Handle<JSReceiver> then,
Handle<JSFunction> resolve, Handle<JSFunction> reject, Handle<JSFunction> resolve, Handle<JSFunction> reject,
Handle<Object> debug_id, Handle<Object> debug_name); Handle<Object> debug_id, Handle<Object> debug_name,
Handle<Context> context);
// Create a new PrototypeInfo struct. // Create a new PrototypeInfo struct.
Handle<PrototypeInfo> NewPrototypeInfo(); Handle<PrototypeInfo> NewPrototypeInfo();
......
...@@ -3257,9 +3257,8 @@ void Isolate::RunMicrotasksInternal() { ...@@ -3257,9 +3257,8 @@ void Isolate::RunMicrotasksInternal() {
if (microtask->IsJSFunction()) { if (microtask->IsJSFunction()) {
context = Handle<JSFunction>::cast(microtask)->context(); context = Handle<JSFunction>::cast(microtask)->context();
} else if (microtask->IsPromiseResolveThenableJobInfo()) { } else if (microtask->IsPromiseResolveThenableJobInfo()) {
context = Handle<PromiseResolveThenableJobInfo>::cast(microtask) context =
->resolve() Handle<PromiseResolveThenableJobInfo>::cast(microtask)->context();
->context();
} else { } else {
context = Handle<PromiseReactionJobInfo>::cast(microtask)->context(); context = Handle<PromiseReactionJobInfo>::cast(microtask)->context();
} }
......
...@@ -266,16 +266,11 @@ function ResolvePromise(promise, resolution) { ...@@ -266,16 +266,11 @@ function ResolvePromise(promise, resolution) {
} }
if (IS_CALLABLE(then)) { if (IS_CALLABLE(then)) {
// TODO(gsathya): Remove container for callbacks when this is
// moved to CPP/TF.
var callbacks = %create_resolving_functions(promise, false);
if (DEBUG_IS_ACTIVE && IsPromise(resolution)) { if (DEBUG_IS_ACTIVE && IsPromise(resolution)) {
// Mark the dependency of the new promise on the resolution // Mark the dependency of the new promise on the resolution
SET_PRIVATE(resolution, promiseHandledBySymbol, promise); SET_PRIVATE(resolution, promiseHandledBySymbol, promise);
} }
%EnqueuePromiseResolveThenableJob( %EnqueuePromiseResolveThenableJob(promise, resolution, then);
resolution, then, callbacks[kResolveCallback],
callbacks[kRejectCallback]);
return; return;
} }
} }
......
...@@ -972,6 +972,7 @@ void PromiseResolveThenableJobInfo::PromiseResolveThenableJobInfoVerify() { ...@@ -972,6 +972,7 @@ void PromiseResolveThenableJobInfo::PromiseResolveThenableJobInfoVerify() {
CHECK(reject()->IsJSFunction()); CHECK(reject()->IsJSFunction());
CHECK(debug_id()->IsNumber() || debug_id()->IsUndefined(isolate)); CHECK(debug_id()->IsNumber() || debug_id()->IsUndefined(isolate));
CHECK(debug_name()->IsString() || debug_name()->IsUndefined(isolate)); CHECK(debug_name()->IsString() || debug_name()->IsUndefined(isolate));
CHECK(context()->IsContext());
} }
void PromiseReactionJobInfo::PromiseReactionJobInfoVerify() { void PromiseReactionJobInfo::PromiseReactionJobInfoVerify() {
......
...@@ -5698,6 +5698,7 @@ ACCESSORS(PromiseResolveThenableJobInfo, resolve, JSFunction, kResolveOffset) ...@@ -5698,6 +5698,7 @@ ACCESSORS(PromiseResolveThenableJobInfo, resolve, JSFunction, kResolveOffset)
ACCESSORS(PromiseResolveThenableJobInfo, reject, JSFunction, kRejectOffset) ACCESSORS(PromiseResolveThenableJobInfo, reject, JSFunction, kRejectOffset)
ACCESSORS(PromiseResolveThenableJobInfo, debug_id, Object, kDebugIdOffset) ACCESSORS(PromiseResolveThenableJobInfo, debug_id, Object, kDebugIdOffset)
ACCESSORS(PromiseResolveThenableJobInfo, debug_name, Object, kDebugNameOffset) ACCESSORS(PromiseResolveThenableJobInfo, debug_name, Object, kDebugNameOffset)
ACCESSORS(PromiseResolveThenableJobInfo, context, Context, kContextOffset);
ACCESSORS(PromiseReactionJobInfo, value, Object, kValueOffset); ACCESSORS(PromiseReactionJobInfo, value, Object, kValueOffset);
ACCESSORS(PromiseReactionJobInfo, tasks, Object, kTasksOffset); ACCESSORS(PromiseReactionJobInfo, tasks, Object, kTasksOffset);
......
...@@ -1171,6 +1171,7 @@ void PromiseResolveThenableJobInfo::PromiseResolveThenableJobInfoPrint( ...@@ -1171,6 +1171,7 @@ void PromiseResolveThenableJobInfo::PromiseResolveThenableJobInfoPrint(
os << "\n - reject: " << Brief(reject()); os << "\n - reject: " << Brief(reject());
os << "\n - debug id: " << Brief(debug_id()); os << "\n - debug id: " << Brief(debug_id());
os << "\n - debug name: " << Brief(debug_name()); os << "\n - debug name: " << Brief(debug_name());
os << "\n - context: " << Brief(context());
os << "\n"; os << "\n";
} }
......
...@@ -6812,6 +6812,7 @@ class PromiseResolveThenableJobInfo : public Struct { ...@@ -6812,6 +6812,7 @@ class PromiseResolveThenableJobInfo : public Struct {
DECL_ACCESSORS(reject, JSFunction) DECL_ACCESSORS(reject, JSFunction)
DECL_ACCESSORS(debug_id, Object) DECL_ACCESSORS(debug_id, Object)
DECL_ACCESSORS(debug_name, Object) DECL_ACCESSORS(debug_name, Object)
DECL_ACCESSORS(context, Context)
static const int kThenableOffset = Struct::kHeaderSize; static const int kThenableOffset = Struct::kHeaderSize;
static const int kThenOffset = kThenableOffset + kPointerSize; static const int kThenOffset = kThenableOffset + kPointerSize;
...@@ -6819,7 +6820,8 @@ class PromiseResolveThenableJobInfo : public Struct { ...@@ -6819,7 +6820,8 @@ class PromiseResolveThenableJobInfo : public Struct {
static const int kRejectOffset = kResolveOffset + kPointerSize; static const int kRejectOffset = kResolveOffset + kPointerSize;
static const int kDebugIdOffset = kRejectOffset + kPointerSize; static const int kDebugIdOffset = kRejectOffset + kPointerSize;
static const int kDebugNameOffset = kDebugIdOffset + kPointerSize; static const int kDebugNameOffset = kDebugIdOffset + kPointerSize;
static const int kSize = kDebugNameOffset + kPointerSize; static const int kContextOffset = kDebugNameOffset + kPointerSize;
static const int kSize = kContextOffset + kPointerSize;
DECLARE_CAST(PromiseResolveThenableJobInfo) DECLARE_CAST(PromiseResolveThenableJobInfo)
DECLARE_PRINTER(PromiseResolveThenableJobInfo) DECLARE_PRINTER(PromiseResolveThenableJobInfo)
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/promise-utils.h"
#include "src/factory.h"
#include "src/isolate.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
enum PromiseResolvingFunctionContextSlot {
kAlreadyVisitedSlot = Context::MIN_CONTEXT_SLOTS,
kPromiseSlot,
kDebugEventSlot,
kPromiseContextLength,
};
JSObject* PromiseUtils::GetPromise(Handle<Context> context) {
return JSObject::cast(context->get(kPromiseSlot));
}
Object* PromiseUtils::GetDebugEvent(Handle<Context> context) {
return context->get(kDebugEventSlot);
}
bool PromiseUtils::HasAlreadyVisited(Handle<Context> context) {
return Smi::cast(context->get(kAlreadyVisitedSlot))->value() != 0;
}
void PromiseUtils::SetAlreadyVisited(Handle<Context> context) {
context->set(kAlreadyVisitedSlot, Smi::FromInt(1));
}
void PromiseUtils::CreateResolvingFunctions(Isolate* isolate,
Handle<JSObject> promise,
Handle<Object> debug_event,
Handle<JSFunction>* resolve,
Handle<JSFunction>* reject) {
DCHECK(debug_event->IsTrue(isolate) || debug_event->IsFalse(isolate));
Handle<Context> context =
isolate->factory()->NewPromiseResolvingFunctionContext(
kPromiseContextLength);
context->set_native_context(*isolate->native_context());
context->set(kAlreadyVisitedSlot, Smi::kZero);
context->set(kPromiseSlot, *promise);
context->set(kDebugEventSlot, *debug_event);
Handle<SharedFunctionInfo> resolve_shared_fun(
isolate->native_context()->promise_resolve_shared_fun(), isolate);
Handle<JSFunction> resolve_fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
isolate->sloppy_function_without_prototype_map(), resolve_shared_fun,
isolate->native_context(), TENURED);
Handle<SharedFunctionInfo> reject_shared_fun(
isolate->native_context()->promise_reject_shared_fun(), isolate);
Handle<JSFunction> reject_fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
isolate->sloppy_function_without_prototype_map(), reject_shared_fun,
isolate->native_context(), TENURED);
resolve_fun->set_context(*context);
reject_fun->set_context(*context);
*resolve = resolve_fun;
*reject = reject_fun;
}
} // namespace internal
} // namespace v8
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_PROMISE_UTILS_H_
#define V8_PROMISE_UTILS_H_
#include "src/objects.h"
namespace v8 {
namespace internal {
// Helper methods for Promise builtins.
class PromiseUtils : public AllStatic {
public:
// These get and set the slots on the PromiseResolvingContext, which
// is used by the resolve/reject promise callbacks.
static JSObject* GetPromise(Handle<Context> context);
static Object* GetDebugEvent(Handle<Context> context);
static bool HasAlreadyVisited(Handle<Context> context);
static void SetAlreadyVisited(Handle<Context> context);
static void CreateResolvingFunctions(Isolate* isolate,
Handle<JSObject> promise,
Handle<Object> debug_event,
Handle<JSFunction>* resolve,
Handle<JSFunction>* reject);
};
} // namespace internal
} // namespace v8
#endif // V8_PROMISE_UTILS_H_
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "src/debug/debug.h" #include "src/debug/debug.h"
#include "src/elements.h" #include "src/elements.h"
#include "src/promise-utils.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -139,13 +140,19 @@ RUNTIME_FUNCTION(Runtime_EnqueuePromiseReactionJob) { ...@@ -139,13 +140,19 @@ RUNTIME_FUNCTION(Runtime_EnqueuePromiseReactionJob) {
RUNTIME_FUNCTION(Runtime_EnqueuePromiseResolveThenableJob) { RUNTIME_FUNCTION(Runtime_EnqueuePromiseResolveThenableJob) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 4); DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, resolution, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, then, 1); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, resolution, 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, resolve, 2); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, then, 2);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, reject, 3);
Handle<Object> debug_id; // TODO(gsathya): Add fast path for native promises with unmodified
Handle<Object> debug_name; // PromiseThen (which don't need these resolving functions, but
// instead can just call resolve/reject directly).
Handle<JSFunction> resolve, reject;
PromiseUtils::CreateResolvingFunctions(
isolate, promise, isolate->factory()->false_value(), &resolve, &reject);
Handle<Object> debug_id, debug_name;
if (isolate->debug()->is_active()) { if (isolate->debug()->is_active()) {
debug_id = debug_id =
handle(Smi::FromInt(isolate->GetNextDebugMicrotaskId()), isolate); handle(Smi::FromInt(isolate->GetNextDebugMicrotaskId()), isolate);
...@@ -157,10 +164,13 @@ RUNTIME_FUNCTION(Runtime_EnqueuePromiseResolveThenableJob) { ...@@ -157,10 +164,13 @@ RUNTIME_FUNCTION(Runtime_EnqueuePromiseResolveThenableJob) {
debug_id = isolate->factory()->undefined_value(); debug_id = isolate->factory()->undefined_value();
debug_name = isolate->factory()->undefined_value(); debug_name = isolate->factory()->undefined_value();
} }
Handle<PromiseResolveThenableJobInfo> info = Handle<PromiseResolveThenableJobInfo> info =
isolate->factory()->NewPromiseResolveThenableJobInfo( isolate->factory()->NewPromiseResolveThenableJobInfo(
resolution, then, resolve, reject, debug_id, debug_name); resolution, then, resolve, reject, debug_id, debug_name,
isolate->native_context());
isolate->EnqueueMicrotask(info); isolate->EnqueueMicrotask(info);
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
......
...@@ -294,7 +294,7 @@ namespace internal { ...@@ -294,7 +294,7 @@ namespace internal {
F(CreateListFromArrayLike, 1, 1) \ F(CreateListFromArrayLike, 1, 1) \
F(EnqueueMicrotask, 1, 1) \ F(EnqueueMicrotask, 1, 1) \
F(EnqueuePromiseReactionJob, 4, 1) \ F(EnqueuePromiseReactionJob, 4, 1) \
F(EnqueuePromiseResolveThenableJob, 4, 1) \ F(EnqueuePromiseResolveThenableJob, 3, 1) \
F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \ F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \
F(ExportExperimentalFromRuntime, 1, 1) \ F(ExportExperimentalFromRuntime, 1, 1) \
F(ExportFromRuntime, 1, 1) \ F(ExportFromRuntime, 1, 1) \
......
...@@ -1108,6 +1108,8 @@ ...@@ -1108,6 +1108,8 @@
'profiler/tracing-cpu-profiler.h', 'profiler/tracing-cpu-profiler.h',
'profiler/unbound-queue-inl.h', 'profiler/unbound-queue-inl.h',
'profiler/unbound-queue.h', 'profiler/unbound-queue.h',
'promise-utils.h',
'promise-utils.cc',
'property-descriptor.cc', 'property-descriptor.cc',
'property-descriptor.h', 'property-descriptor.h',
'property-details.h', 'property-details.h',
......
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