[promises] cleanup default promise handlers

Use private symbols to mark default promise handler, instead of calling out to default
handlers defined in JS. We check for this symbol in PromiseHandle and perform the
appropriate behavior as the default handlers.

Catch prediction logic is updated to account for a symbol.

BUG=v8:5343

Review-Url: https://codereview.chromium.org/2695593002
Cr-Commit-Position: refs/heads/master@{#43135}
This commit is contained in:
gsathya 2017-02-12 22:31:11 -08:00 committed by Commit bot
parent 299f834058
commit 31bc17f006
7 changed files with 96 additions and 67 deletions

View File

@ -420,7 +420,6 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(
Node* context, Node* promise, Node* on_resolve, Node* on_reject,
Node* deferred_promise, Node* deferred_on_resolve,
Node* deferred_on_reject) {
Node* const native_context = LoadNativeContext(context);
Variable var_on_resolve(this, MachineRepresentation::kTagged),
var_on_reject(this, MachineRepresentation::kTagged);
@ -432,14 +431,17 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(
append_callbacks(this);
GotoIf(TaggedIsSmi(on_resolve), &if_onresolvenotcallable);
Isolate* isolate = this->isolate();
Node* const on_resolve_map = LoadMap(on_resolve);
Branch(IsCallableMap(on_resolve_map), &onrejectcheck,
&if_onresolvenotcallable);
Bind(&if_onresolvenotcallable);
{
var_on_resolve.Bind(LoadContextElement(
native_context, Context::PROMISE_ID_RESOLVE_HANDLER_INDEX));
Isolate* isolate = this->isolate();
Node* const default_resolve_handler_symbol = HeapConstant(
isolate->factory()->promise_default_resolve_handler_symbol());
var_on_resolve.Bind(default_resolve_handler_symbol);
Goto(&onrejectcheck);
}
@ -454,8 +456,9 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(
Bind(&if_onrejectnotcallable);
{
var_on_reject.Bind(LoadContextElement(
native_context, Context::PROMISE_ID_REJECT_HANDLER_INDEX));
Node* const default_reject_handler_symbol = HeapConstant(
isolate->factory()->promise_default_reject_handler_symbol());
var_on_reject.Bind(default_reject_handler_symbol);
Goto(&append_callbacks);
}
}
@ -1265,25 +1268,55 @@ TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) {
Bind(&run_handler);
{
Callable call_callable = CodeFactory::Call(isolate);
Node* const result =
CallJS(call_callable, context, handler, UndefinedConstant(), value);
Label if_defaulthandler(this), if_callablehandler(this),
if_internalhandler(this), if_customhandler(this, Label::kDeferred);
Variable var_result(this, MachineRepresentation::kTagged);
GotoIfException(result, &if_rejectpromise, &var_reason);
Branch(IsSymbol(handler), &if_defaulthandler, &if_callablehandler);
Label if_internalhandler(this), if_customhandler(this, Label::kDeferred);
Branch(IsUndefined(deferred_on_resolve), &if_internalhandler,
&if_customhandler);
Bind(&if_defaulthandler);
{
Label if_resolve(this), if_reject(this);
Node* const default_resolve_handler_symbol = HeapConstant(
isolate->factory()->promise_default_resolve_handler_symbol());
Branch(WordEqual(default_resolve_handler_symbol, handler), &if_resolve,
&if_reject);
Bind(&if_resolve);
{
var_result.Bind(value);
Branch(IsUndefined(deferred_on_resolve), &if_internalhandler,
&if_customhandler);
}
Bind(&if_reject);
{
var_reason.Bind(value);
Goto(&if_rejectpromise);
}
}
Bind(&if_callablehandler);
{
Callable call_callable = CodeFactory::Call(isolate);
Node* const result =
CallJS(call_callable, context, handler, UndefinedConstant(), value);
var_result.Bind(result);
GotoIfException(result, &if_rejectpromise, &var_reason);
Branch(IsUndefined(deferred_on_resolve), &if_internalhandler,
&if_customhandler);
}
Bind(&if_internalhandler);
InternalResolvePromise(context, deferred_promise, result);
InternalResolvePromise(context, deferred_promise, var_result.value());
Goto(&promisehook_after);
Bind(&if_customhandler);
{
Callable call_callable = CodeFactory::Call(isolate);
Node* const maybe_exception =
CallJS(call_callable, context, deferred_on_resolve,
UndefinedConstant(), result);
UndefinedConstant(), var_result.value());
GotoIfException(maybe_exception, &if_rejectpromise, &var_reason);
Goto(&promisehook_after);
}

View File

@ -107,8 +107,6 @@ enum ContextLookupFlags {
V(OBJECT_TO_STRING, JSFunction, object_to_string) \
V(PROMISE_CATCH_INDEX, JSFunction, promise_catch) \
V(PROMISE_FUNCTION_INDEX, JSFunction, promise_function) \
V(PROMISE_ID_RESOLVE_HANDLER_INDEX, JSFunction, promise_id_resolve_handler) \
V(PROMISE_ID_REJECT_HANDLER_INDEX, JSFunction, promise_id_reject_handler) \
V(RANGE_ERROR_FUNCTION_INDEX, JSFunction, range_error_function) \
V(REFERENCE_ERROR_FUNCTION_INDEX, JSFunction, reference_error_function) \
V(SET_ADD_METHOD_INDEX, JSFunction, set_add) \

View File

@ -207,40 +207,42 @@
V(writable_string, "writable") \
V(year_string, "year")
#define PRIVATE_SYMBOL_LIST(V) \
V(array_iteration_kind_symbol) \
V(array_iterator_next_symbol) \
V(array_iterator_object_symbol) \
V(call_site_frame_array_symbol) \
V(call_site_frame_index_symbol) \
V(class_end_position_symbol) \
V(class_start_position_symbol) \
V(detailed_stack_trace_symbol) \
V(elements_transition_symbol) \
V(error_end_pos_symbol) \
V(error_script_symbol) \
V(error_start_pos_symbol) \
V(frozen_symbol) \
V(hash_code_symbol) \
V(home_object_symbol) \
V(intl_initialized_marker_symbol) \
V(intl_pattern_symbol) \
V(intl_resolved_symbol) \
V(megamorphic_symbol) \
V(native_context_index_symbol) \
V(nonexistent_symbol) \
V(nonextensible_symbol) \
V(normal_ic_symbol) \
V(not_mapped_symbol) \
V(premonomorphic_symbol) \
V(promise_async_stack_id_symbol) \
V(promise_debug_marker_symbol) \
V(promise_forwarding_handler_symbol) \
V(promise_handled_by_symbol) \
V(promise_async_id_symbol) \
V(sealed_symbol) \
V(stack_trace_symbol) \
V(strict_function_transition_symbol) \
#define PRIVATE_SYMBOL_LIST(V) \
V(array_iteration_kind_symbol) \
V(array_iterator_next_symbol) \
V(array_iterator_object_symbol) \
V(call_site_frame_array_symbol) \
V(call_site_frame_index_symbol) \
V(class_end_position_symbol) \
V(class_start_position_symbol) \
V(detailed_stack_trace_symbol) \
V(elements_transition_symbol) \
V(error_end_pos_symbol) \
V(error_script_symbol) \
V(error_start_pos_symbol) \
V(frozen_symbol) \
V(hash_code_symbol) \
V(home_object_symbol) \
V(intl_initialized_marker_symbol) \
V(intl_pattern_symbol) \
V(intl_resolved_symbol) \
V(megamorphic_symbol) \
V(native_context_index_symbol) \
V(nonexistent_symbol) \
V(nonextensible_symbol) \
V(normal_ic_symbol) \
V(not_mapped_symbol) \
V(premonomorphic_symbol) \
V(promise_async_stack_id_symbol) \
V(promise_debug_marker_symbol) \
V(promise_forwarding_handler_symbol) \
V(promise_handled_by_symbol) \
V(promise_async_id_symbol) \
V(promise_default_resolve_handler_symbol) \
V(promise_default_reject_handler_symbol) \
V(sealed_symbol) \
V(stack_trace_symbol) \
V(strict_function_transition_symbol) \
V(uninitialized_symbol)
#define PUBLIC_SYMBOL_LIST(V) \

View File

@ -1878,6 +1878,11 @@ bool InternalPromiseHasUserDefinedRejectHandler(Isolate* isolate,
Handle<JSReceiver>::cast(deferred_promise));
}
if (queue->IsSymbol()) {
return InternalPromiseHasUserDefinedRejectHandler(
isolate, Handle<JSPromise>::cast(deferred_promise));
}
Handle<FixedArray> queue_arr = Handle<FixedArray>::cast(queue);
Handle<FixedArray> deferred_promise_arr =
Handle<FixedArray>::cast(deferred_promise);

View File

@ -18,14 +18,6 @@ var promiseForwardingHandlerSymbol =
utils.ImportNow("promise_forwarding_handler_symbol");
var GlobalPromise = global.Promise;
// -------------------------------------------------------------------
// Core functionality.
function PromiseIdResolveHandler(x) { return x; }
function PromiseIdRejectHandler(r) { %_ReThrow(r); }
SET_PRIVATE(PromiseIdRejectHandler, promiseForwardingHandlerSymbol, true);
// -------------------------------------------------------------------
// Define exported functions.
@ -137,9 +129,4 @@ utils.InstallFunctions(GlobalPromise, DONT_ENUM, [
"race", PromiseRace,
]);
%InstallToContext([
"promise_id_resolve_handler", PromiseIdResolveHandler,
"promise_id_reject_handler", PromiseIdRejectHandler
]);
})

View File

@ -922,10 +922,11 @@ void JSPromise::JSPromiseVerify() {
deferred_on_reject()->IsCallable() ||
deferred_on_reject()->IsFixedArray());
CHECK(fulfill_reactions()->IsUndefined(isolate) ||
fulfill_reactions()->IsCallable() ||
fulfill_reactions()->IsCallable() || fulfill_reactions()->IsSymbol() ||
fulfill_reactions()->IsFixedArray());
CHECK(reject_reactions()->IsUndefined(isolate) ||
reject_reactions()->IsCallable() || reject_reactions()->IsFixedArray());
reject_reactions()->IsSymbol() || reject_reactions()->IsCallable() ||
reject_reactions()->IsFixedArray());
}
void JSRegExp::JSRegExpVerify() {
@ -1051,7 +1052,8 @@ void PromiseReactionJobInfo::PromiseReactionJobInfoVerify() {
Isolate* isolate = GetIsolate();
CHECK(IsPromiseReactionJobInfo());
CHECK(value()->IsObject());
CHECK(tasks()->IsFixedArray() || tasks()->IsCallable());
CHECK(tasks()->IsFixedArray() || tasks()->IsCallable() ||
tasks()->IsSymbol());
CHECK(deferred_promise()->IsUndefined(isolate) ||
deferred_promise()->IsJSReceiver() ||
deferred_promise()->IsFixedArray());

View File

@ -8507,13 +8507,15 @@ class JSPromise : public JSObject {
// 1) Undefined -- This is the zero state when there is no callback
// or deferred fields registered.
//
// 2) Object -- There is a single Callable directly attached to the
// 2) Object -- There is a single callback directly attached to the
// fulfill_reactions, reject_reactions and the deferred fields are
// directly attached to the slots. In this state, deferred_promise
// is a JSReceiver and deferred_on_{resolve, reject} are Callables.
//
// 3) FixedArray -- There is more than one callback and deferred
// fields attached to a FixedArray.
//
// The callback can be a Callable or a Symbol.
DECL_ACCESSORS(deferred_promise, Object)
DECL_ACCESSORS(deferred_on_resolve, Object)
DECL_ACCESSORS(deferred_on_reject, Object)