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") {
"src/profiler/tracing-cpu-profiler.h",
"src/profiler/unbound-queue-inl.h",
"src/profiler/unbound-queue.h",
"src/promise-utils.cc",
"src/promise-utils.h",
"src/property-descriptor.cc",
"src/property-descriptor.h",
"src/property-details.h",
......
// 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/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/promise-utils.h"
namespace v8 {
namespace internal {
enum PromiseResolvingFunctionContextSlot {
kAlreadyVisitedSlot = Context::MIN_CONTEXT_SLOTS,
kPromiseSlot,
kDebugEventSlot,
kPromiseContextLength,
};
// ES#sec-promise-resolve-functions
// Promise Resolve Functions
BUILTIN(PromiseResolveClosure) {
HandleScope scope(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();
}
context->set(kAlreadyVisitedSlot, Smi::FromInt(1));
Handle<JSObject> promise(JSObject::cast(context->get(kPromiseSlot)), isolate);
PromiseUtils::SetAlreadyVisited(context);
Handle<JSObject> promise = handle(PromiseUtils::GetPromise(context), isolate);
Handle<Object> value = args.atOrUndefined(isolate, 1);
MaybeHandle<Object> maybe_result;
......@@ -46,18 +40,16 @@ BUILTIN(PromiseRejectClosure) {
HandleScope scope(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();
}
context->set(kAlreadyVisitedSlot, Smi::FromInt(1));
PromiseUtils::SetAlreadyVisited(context);
Handle<Object> value = args.atOrUndefined(isolate, 1);
Handle<JSObject> promise(JSObject::cast(context->get(kPromiseSlot)), isolate);
Handle<Object> debug_event(context->get(kDebugEventSlot), isolate);
Handle<JSObject> promise = handle(PromiseUtils::GetPromise(context), isolate);
Handle<Object> debug_event =
handle(PromiseUtils::GetDebugEvent(context), isolate);
MaybeHandle<Object> maybe_result;
Handle<Object> argv[] = {promise, value, debug_event};
RETURN_FAILURE_ON_EXCEPTION(
......@@ -75,31 +67,10 @@ BUILTIN(CreateResolvingFunctions) {
Handle<JSObject> promise = args.at<JSObject>(1);
Handle<Object> debug_event = args.at<Object>(2);
Handle<JSFunction> resolve, reject;
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 =
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);
PromiseUtils::CreateResolvingFunctions(isolate, promise, debug_event,
&resolve, &reject);
Handle<FixedArray> result = isolate->factory()->NewFixedArray(2);
result->set(0, *resolve);
......
......@@ -981,7 +981,8 @@ Handle<Struct> Factory::NewStruct(InstanceType type) {
Handle<PromiseResolveThenableJobInfo> Factory::NewPromiseResolveThenableJobInfo(
Handle<JSReceiver> thenable, Handle<JSReceiver> then,
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>::cast(
NewStruct(PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE));
......@@ -991,6 +992,7 @@ Handle<PromiseResolveThenableJobInfo> Factory::NewPromiseResolveThenableJobInfo(
result->set_reject(*reject);
result->set_debug_id(*debug_id);
result->set_debug_name(*debug_name);
result->set_context(*context);
return result;
}
......
......@@ -71,7 +71,8 @@ class V8_EXPORT_PRIVATE Factory final {
Handle<PromiseResolveThenableJobInfo> NewPromiseResolveThenableJobInfo(
Handle<JSReceiver> thenable, Handle<JSReceiver> then,
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.
Handle<PrototypeInfo> NewPrototypeInfo();
......
......@@ -3257,9 +3257,8 @@ void Isolate::RunMicrotasksInternal() {
if (microtask->IsJSFunction()) {
context = Handle<JSFunction>::cast(microtask)->context();
} else if (microtask->IsPromiseResolveThenableJobInfo()) {
context = Handle<PromiseResolveThenableJobInfo>::cast(microtask)
->resolve()
->context();
context =
Handle<PromiseResolveThenableJobInfo>::cast(microtask)->context();
} else {
context = Handle<PromiseReactionJobInfo>::cast(microtask)->context();
}
......
......@@ -266,16 +266,11 @@ function ResolvePromise(promise, resolution) {
}
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)) {
// Mark the dependency of the new promise on the resolution
SET_PRIVATE(resolution, promiseHandledBySymbol, promise);
}
%EnqueuePromiseResolveThenableJob(
resolution, then, callbacks[kResolveCallback],
callbacks[kRejectCallback]);
%EnqueuePromiseResolveThenableJob(promise, resolution, then);
return;
}
}
......
......@@ -972,6 +972,7 @@ void PromiseResolveThenableJobInfo::PromiseResolveThenableJobInfoVerify() {
CHECK(reject()->IsJSFunction());
CHECK(debug_id()->IsNumber() || debug_id()->IsUndefined(isolate));
CHECK(debug_name()->IsString() || debug_name()->IsUndefined(isolate));
CHECK(context()->IsContext());
}
void PromiseReactionJobInfo::PromiseReactionJobInfoVerify() {
......
......@@ -5698,6 +5698,7 @@ ACCESSORS(PromiseResolveThenableJobInfo, resolve, JSFunction, kResolveOffset)
ACCESSORS(PromiseResolveThenableJobInfo, reject, JSFunction, kRejectOffset)
ACCESSORS(PromiseResolveThenableJobInfo, debug_id, Object, kDebugIdOffset)
ACCESSORS(PromiseResolveThenableJobInfo, debug_name, Object, kDebugNameOffset)
ACCESSORS(PromiseResolveThenableJobInfo, context, Context, kContextOffset);
ACCESSORS(PromiseReactionJobInfo, value, Object, kValueOffset);
ACCESSORS(PromiseReactionJobInfo, tasks, Object, kTasksOffset);
......
......@@ -1171,6 +1171,7 @@ void PromiseResolveThenableJobInfo::PromiseResolveThenableJobInfoPrint(
os << "\n - reject: " << Brief(reject());
os << "\n - debug id: " << Brief(debug_id());
os << "\n - debug name: " << Brief(debug_name());
os << "\n - context: " << Brief(context());
os << "\n";
}
......
......@@ -6812,6 +6812,7 @@ class PromiseResolveThenableJobInfo : public Struct {
DECL_ACCESSORS(reject, JSFunction)
DECL_ACCESSORS(debug_id, Object)
DECL_ACCESSORS(debug_name, Object)
DECL_ACCESSORS(context, Context)
static const int kThenableOffset = Struct::kHeaderSize;
static const int kThenOffset = kThenableOffset + kPointerSize;
......@@ -6819,7 +6820,8 @@ class PromiseResolveThenableJobInfo : public Struct {
static const int kRejectOffset = kResolveOffset + kPointerSize;
static const int kDebugIdOffset = kRejectOffset + 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_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 @@
#include "src/debug/debug.h"
#include "src/elements.h"
#include "src/promise-utils.h"
namespace v8 {
namespace internal {
......@@ -139,13 +140,19 @@ RUNTIME_FUNCTION(Runtime_EnqueuePromiseReactionJob) {
RUNTIME_FUNCTION(Runtime_EnqueuePromiseResolveThenableJob) {
HandleScope scope(isolate);
DCHECK(args.length() == 4);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, resolution, 0);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, then, 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, resolve, 2);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, reject, 3);
Handle<Object> debug_id;
Handle<Object> debug_name;
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, resolution, 1);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, then, 2);
// TODO(gsathya): Add fast path for native promises with unmodified
// 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()) {
debug_id =
handle(Smi::FromInt(isolate->GetNextDebugMicrotaskId()), isolate);
......@@ -157,10 +164,13 @@ RUNTIME_FUNCTION(Runtime_EnqueuePromiseResolveThenableJob) {
debug_id = isolate->factory()->undefined_value();
debug_name = isolate->factory()->undefined_value();
}
Handle<PromiseResolveThenableJobInfo> info =
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);
return isolate->heap()->undefined_value();
}
......
......@@ -294,7 +294,7 @@ namespace internal {
F(CreateListFromArrayLike, 1, 1) \
F(EnqueueMicrotask, 1, 1) \
F(EnqueuePromiseReactionJob, 4, 1) \
F(EnqueuePromiseResolveThenableJob, 4, 1) \
F(EnqueuePromiseResolveThenableJob, 3, 1) \
F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \
F(ExportExperimentalFromRuntime, 1, 1) \
F(ExportFromRuntime, 1, 1) \
......
......@@ -1108,6 +1108,8 @@
'profiler/tracing-cpu-profiler.h',
'profiler/unbound-queue-inl.h',
'profiler/unbound-queue.h',
'promise-utils.h',
'promise-utils.cc',
'property-descriptor.cc',
'property-descriptor.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