Commit 30b564c7 authored by gsathya's avatar gsathya Committed by Commit bot

Object

-- New JSObject for promises: JSPromise

Builtins
-- PromiseThen TFJ
-- PromiseCreateAndSet TFJ for internal use
-- PerformPromiseThen TFJ for internal use
-- PromiseInit for initial promise setup
-- SpeciesConstructor for use in PromiseThen
-- ThrowIfNotJSReceiver for use in SpeciesConstructor
-- AppendPromiseCallback to update FixedArray with new callback
-- InternalPerformPromiseThen

Promises.js
-- Cleanup unused symbols
-- Remove PerformPromiseThen
-- Remove PromiseThen
-- Remove PromiseSet
-- Remove PromiseAttachCallbacks

Runtime
-- PromiseSet to set promise inobject values
-- Refactor functions to use FixedArrays for callbacks instead of
   JSArray
-- Runtime_PromiseStatus to return promise status
-- Runtime_PromiseResult to return promise result
-- Runtime_PromiseDeferred to return deferred attached to promise
-- Runtime_PromiseRejectReactions to return reject reactions attached
   to promise

This CL results in a 13.07% improvement in the promises benchmark
(over 5 runs).

BUG=v8:5343

Review-Url: https://codereview.chromium.org/2536463002
Cr-Commit-Position: refs/heads/master@{#41503}
parent 7036eec6
...@@ -1795,9 +1795,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1795,9 +1795,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Handle<JSObject> prototype = Handle<JSObject> prototype =
factory->NewJSObject(isolate->object_function(), TENURED); factory->NewJSObject(isolate->object_function(), TENURED);
Handle<JSFunction> promise_fun = InstallFunction( Handle<JSFunction> promise_fun =
global, "Promise", JS_PROMISE_TYPE, JSObject::kHeaderSize, prototype, InstallFunction(global, "Promise", JS_PROMISE_TYPE, JSPromise::kSize,
Builtins::kPromiseConstructor); prototype, Builtins::kPromiseConstructor);
InstallWithIntrinsicDefaultProto(isolate, promise_fun, InstallWithIntrinsicDefaultProto(isolate, promise_fun,
Context::PROMISE_FUNCTION_INDEX); Context::PROMISE_FUNCTION_INDEX);
...@@ -1816,6 +1816,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1816,6 +1816,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
prototype, factory->to_string_tag_symbol(), factory->Promise_string(), prototype, factory->to_string_tag_symbol(), factory->Promise_string(),
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)); static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
SimpleInstallFunction(prototype, "then", Builtins::kPromiseThen, 2, true,
DONT_ENUM);
{ // Internal: PromiseInternalConstructor { // Internal: PromiseInternalConstructor
Handle<JSFunction> function = Handle<JSFunction> function =
SimpleCreateFunction(isolate, factory->empty_string(), SimpleCreateFunction(isolate, factory->empty_string(),
...@@ -1824,6 +1827,14 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1824,6 +1827,14 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
isolate, function, Context::PROMISE_INTERNAL_CONSTRUCTOR_INDEX); isolate, function, Context::PROMISE_INTERNAL_CONSTRUCTOR_INDEX);
} }
{ // Internal: PromiseCreateAndSet
Handle<JSFunction> function =
SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kPromiseCreateAndSet, 2, false);
InstallWithIntrinsicDefaultProto(isolate, function,
Context::PROMISE_CREATE_AND_SET_INDEX);
}
{ // Internal: IsPromise { // Internal: IsPromise
Handle<JSFunction> function = SimpleCreateFunction( Handle<JSFunction> function = SimpleCreateFunction(
isolate, factory->empty_string(), Builtins::kIsPromise, 1, false); isolate, factory->empty_string(), Builtins::kIsPromise, 1, false);
...@@ -1831,6 +1842,14 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1831,6 +1842,14 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Context::IS_PROMISE_INDEX); Context::IS_PROMISE_INDEX);
} }
{ // Internal: PerformPromiseThen
Handle<JSFunction> function =
SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kPerformPromiseThen, 4, false);
InstallWithIntrinsicDefaultProto(isolate, function,
Context::PERFORM_PROMISE_THEN_INDEX);
}
{ {
Handle<Code> code = Handle<Code> code =
handle(isolate->builtins()->builtin(Builtins::kPromiseResolveClosure), handle(isolate->builtins()->builtin(Builtins::kPromiseResolveClosure),
......
This diff is collapsed.
...@@ -567,6 +567,9 @@ namespace internal { ...@@ -567,6 +567,9 @@ namespace internal {
CPP(CreateResolvingFunctions) \ CPP(CreateResolvingFunctions) \
CPP(PromiseResolveClosure) \ CPP(PromiseResolveClosure) \
CPP(PromiseRejectClosure) \ CPP(PromiseRejectClosure) \
TFJ(PromiseThen, 2) \
TFJ(PromiseCreateAndSet, 2) \
TFJ(PerformPromiseThen, 4) \
\ \
/* Proxy */ \ /* Proxy */ \
CPP(ProxyConstructor) \ CPP(ProxyConstructor) \
......
...@@ -63,60 +63,67 @@ enum ContextLookupFlags { ...@@ -63,60 +63,67 @@ enum ContextLookupFlags {
V(CREATE_RESOLVING_FUNCTION_INDEX, JSFunction, create_resolving_functions) \ V(CREATE_RESOLVING_FUNCTION_INDEX, JSFunction, create_resolving_functions) \
V(PROMISE_INTERNAL_CONSTRUCTOR_INDEX, JSFunction, \ V(PROMISE_INTERNAL_CONSTRUCTOR_INDEX, JSFunction, \
promise_internal_constructor) \ promise_internal_constructor) \
V(IS_PROMISE_INDEX, JSFunction, is_promise) V(IS_PROMISE_INDEX, JSFunction, is_promise) \
V(PERFORM_PROMISE_THEN_INDEX, JSFunction, perform_promise_then) \
#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \ V(PROMISE_CREATE_AND_SET_INDEX, JSFunction, promise_create_and_set)
V(ARRAY_CONCAT_INDEX, JSFunction, array_concat) \
V(ARRAY_POP_INDEX, JSFunction, array_pop) \ #define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
V(ARRAY_PUSH_INDEX, JSFunction, array_push) \ V(ARRAY_CONCAT_INDEX, JSFunction, array_concat) \
V(ARRAY_SHIFT_INDEX, JSFunction, array_shift) \ V(ARRAY_POP_INDEX, JSFunction, array_pop) \
V(ARRAY_SPLICE_INDEX, JSFunction, array_splice) \ V(ARRAY_PUSH_INDEX, JSFunction, array_push) \
V(ARRAY_SLICE_INDEX, JSFunction, array_slice) \ V(ARRAY_SHIFT_INDEX, JSFunction, array_shift) \
V(ARRAY_UNSHIFT_INDEX, JSFunction, array_unshift) \ V(ARRAY_SPLICE_INDEX, JSFunction, array_splice) \
V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \ V(ARRAY_SLICE_INDEX, JSFunction, array_slice) \
V(ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX, JSFunction, \ V(ARRAY_UNSHIFT_INDEX, JSFunction, array_unshift) \
async_function_await_caught) \ V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
V(ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX, JSFunction, \ V(ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX, JSFunction, \
async_function_await_uncaught) \ async_function_await_caught) \
V(ASYNC_FUNCTION_PROMISE_CREATE_INDEX, JSFunction, \ V(ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX, JSFunction, \
async_function_promise_create) \ async_function_await_uncaught) \
V(ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, JSFunction, \ V(ASYNC_FUNCTION_PROMISE_CREATE_INDEX, JSFunction, \
async_function_promise_release) \ async_function_promise_create) \
V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \ V(ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, JSFunction, \
V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \ async_function_promise_release) \
V(ERROR_TO_STRING, JSFunction, error_to_string) \ V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \ V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \
V(FUNCTION_HAS_INSTANCE_INDEX, JSFunction, function_has_instance) \ V(ERROR_TO_STRING, JSFunction, error_to_string) \
V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \ V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \
V(MAP_DELETE_METHOD_INDEX, JSFunction, map_delete) \ V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \
V(MAP_GET_METHOD_INDEX, JSFunction, map_get) \ V(MAP_DELETE_METHOD_INDEX, JSFunction, map_delete) \
V(MAP_HAS_METHOD_INDEX, JSFunction, map_has) \ V(MAP_GET_METHOD_INDEX, JSFunction, map_get) \
V(MAP_SET_METHOD_INDEX, JSFunction, map_set) \ V(MAP_HAS_METHOD_INDEX, JSFunction, map_has) \
V(OBJECT_VALUE_OF, JSFunction, object_value_of) \ V(MAP_SET_METHOD_INDEX, JSFunction, map_set) \
V(OBJECT_TO_STRING, JSFunction, object_to_string) \ V(FUNCTION_HAS_INSTANCE_INDEX, JSFunction, function_has_instance) \
V(PROMISE_CATCH_INDEX, JSFunction, promise_catch) \ V(OBJECT_VALUE_OF, JSFunction, object_value_of) \
V(PROMISE_CREATE_INDEX, JSFunction, promise_create) \ V(OBJECT_TO_STRING, JSFunction, object_to_string) \
V(PROMISE_FUNCTION_INDEX, JSFunction, promise_function) \ V(PROMISE_CATCH_INDEX, JSFunction, promise_catch) \
V(PROMISE_HANDLE_INDEX, JSFunction, promise_handle) \ V(PROMISE_CREATE_INDEX, JSFunction, promise_create) \
V(PROMISE_HAS_USER_DEFINED_REJECT_HANDLER_INDEX, JSFunction, \ V(PROMISE_FUNCTION_INDEX, JSFunction, promise_function) \
promise_has_user_defined_reject_handler) \ V(PROMISE_HANDLE_INDEX, JSFunction, promise_handle) \
V(PROMISE_DEBUG_GET_INFO_INDEX, JSFunction, promise_debug_get_info) \ V(PROMISE_HAS_USER_DEFINED_REJECT_HANDLER_INDEX, JSFunction, \
V(PROMISE_REJECT_INDEX, JSFunction, promise_reject) \ promise_has_user_defined_reject_handler) \
V(PROMISE_INTERNAL_REJECT_INDEX, JSFunction, promise_internal_reject) \ V(PROMISE_DEBUG_GET_INFO_INDEX, JSFunction, promise_debug_get_info) \
V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \ V(PROMISE_REJECT_INDEX, JSFunction, promise_reject) \
V(PROMISE_THEN_INDEX, JSFunction, promise_then) \ V(PROMISE_INTERNAL_REJECT_INDEX, JSFunction, promise_internal_reject) \
V(RANGE_ERROR_FUNCTION_INDEX, JSFunction, range_error_function) \ V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
V(REJECT_PROMISE_NO_DEBUG_EVENT_INDEX, JSFunction, \ V(PROMISE_ID_RESOLVE_HANDLER_INDEX, JSFunction, promise_id_resolve_handler) \
reject_promise_no_debug_event) \ V(PROMISE_ID_REJECT_HANDLER_INDEX, JSFunction, promise_id_reject_handler) \
V(REFERENCE_ERROR_FUNCTION_INDEX, JSFunction, reference_error_function) \ V(PROMISE_THEN_INDEX, JSFunction, promise_then) \
V(SET_ADD_METHOD_INDEX, JSFunction, set_add) \ V(NEW_PROMISE_CAPABILITY_INDEX, JSFunction, new_promise_capability) \
V(SET_DELETE_METHOD_INDEX, JSFunction, set_delete) \ V(INTERNAL_PROMISE_CAPABILITY_INDEX, JSFunction, \
V(SET_HAS_METHOD_INDEX, JSFunction, set_has) \ internal_promise_capability) \
V(SYNTAX_ERROR_FUNCTION_INDEX, JSFunction, syntax_error_function) \ V(RANGE_ERROR_FUNCTION_INDEX, JSFunction, range_error_function) \
V(TYPE_ERROR_FUNCTION_INDEX, JSFunction, type_error_function) \ V(REJECT_PROMISE_NO_DEBUG_EVENT_INDEX, JSFunction, \
V(URI_ERROR_FUNCTION_INDEX, JSFunction, uri_error_function) \ reject_promise_no_debug_event) \
V(WASM_COMPILE_ERROR_FUNCTION_INDEX, JSFunction, \ V(REFERENCE_ERROR_FUNCTION_INDEX, JSFunction, reference_error_function) \
wasm_compile_error_function) \ V(SET_ADD_METHOD_INDEX, JSFunction, set_add) \
V(SET_DELETE_METHOD_INDEX, JSFunction, set_delete) \
V(SET_HAS_METHOD_INDEX, JSFunction, set_has) \
V(SYNTAX_ERROR_FUNCTION_INDEX, JSFunction, syntax_error_function) \
V(TYPE_ERROR_FUNCTION_INDEX, JSFunction, type_error_function) \
V(URI_ERROR_FUNCTION_INDEX, JSFunction, uri_error_function) \
V(WASM_COMPILE_ERROR_FUNCTION_INDEX, JSFunction, \
wasm_compile_error_function) \
V(WASM_RUNTIME_ERROR_FUNCTION_INDEX, JSFunction, wasm_runtime_error_function) V(WASM_RUNTIME_ERROR_FUNCTION_INDEX, JSFunction, wasm_runtime_error_function)
#define NATIVE_CONTEXT_JS_ARRAY_ITERATOR_MAPS(V) \ #define NATIVE_CONTEXT_JS_ARRAY_ITERATOR_MAPS(V) \
......
...@@ -13,8 +13,6 @@ var IsNaN = global.isNaN; ...@@ -13,8 +13,6 @@ var IsNaN = global.isNaN;
var JSONStringify = global.JSON.stringify; var JSONStringify = global.JSON.stringify;
var MapEntries; var MapEntries;
var MapIteratorNext; var MapIteratorNext;
var promiseStateSymbol = utils.ImportNow("promise_state_symbol");
var promiseResultSymbol = utils.ImportNow("promise_result_symbol");
var SetIteratorNext; var SetIteratorNext;
var SetValues; var SetValues;
...@@ -1267,7 +1265,7 @@ inherits(PromiseMirror, ObjectMirror); ...@@ -1267,7 +1265,7 @@ inherits(PromiseMirror, ObjectMirror);
function PromiseGetStatus_(value) { function PromiseGetStatus_(value) {
var status = %DebugGetProperty(value, promiseStateSymbol); var status = %PromiseStatus(value);
if (status == 0) return "pending"; if (status == 0) return "pending";
if (status == 1) return "resolved"; if (status == 1) return "resolved";
return "rejected"; return "rejected";
...@@ -1275,7 +1273,7 @@ function PromiseGetStatus_(value) { ...@@ -1275,7 +1273,7 @@ function PromiseGetStatus_(value) {
function PromiseGetValue_(value) { function PromiseGetValue_(value) {
return %DebugGetProperty(value, promiseResultSymbol); return %PromiseResult(value);
} }
......
...@@ -213,16 +213,10 @@ ...@@ -213,16 +213,10 @@
V(premonomorphic_symbol) \ V(premonomorphic_symbol) \
V(promise_async_stack_id_symbol) \ V(promise_async_stack_id_symbol) \
V(promise_debug_marker_symbol) \ V(promise_debug_marker_symbol) \
V(promise_deferred_reaction_symbol) \
V(promise_forwarding_handler_symbol) \ V(promise_forwarding_handler_symbol) \
V(promise_fulfill_reactions_symbol) \
V(promise_handled_by_symbol) \ V(promise_handled_by_symbol) \
V(promise_handled_hint_symbol) \ V(promise_handled_hint_symbol) \
V(promise_has_handler_symbol) \ V(promise_has_handler_symbol) \
V(promise_raw_symbol) \
V(promise_reject_reactions_symbol) \
V(promise_result_symbol) \
V(promise_state_symbol) \
V(sealed_symbol) \ V(sealed_symbol) \
V(stack_trace_symbol) \ V(stack_trace_symbol) \
V(strict_function_transition_symbol) \ V(strict_function_transition_symbol) \
......
...@@ -3176,23 +3176,15 @@ void Isolate::PromiseReactionJob(Handle<PromiseReactionJobInfo> info, ...@@ -3176,23 +3176,15 @@ void Isolate::PromiseReactionJob(Handle<PromiseReactionJobInfo> info,
Handle<Object> tasks(info->tasks(), this); Handle<Object> tasks(info->tasks(), this);
Handle<JSFunction> promise_handle_fn = promise_handle(); Handle<JSFunction> promise_handle_fn = promise_handle();
Handle<Object> undefined = factory()->undefined_value(); Handle<Object> undefined = factory()->undefined_value();
Handle<Object> deferred(info->deferred(), this);
// If tasks is an array we have multiple onFulfilled/onRejected callbacks
// associated with the promise. The deferred object for each callback if (deferred->IsFixedArray()) {
// is attached to this array as well. DCHECK(tasks->IsFixedArray());
// Otherwise, there is a single callback and the deferred object is attached Handle<FixedArray> deferred_arr = Handle<FixedArray>::cast(deferred);
// directly to PromiseReactionJobInfo. Handle<FixedArray> tasks_arr = Handle<FixedArray>::cast(tasks);
if (tasks->IsJSArray()) { for (int i = 0; i < deferred_arr->length(); i++) {
Handle<JSArray> array = Handle<JSArray>::cast(tasks); Handle<Object> argv[] = {value, handle(tasks_arr->get(i), this),
DCHECK(array->length()->IsSmi()); handle(deferred_arr->get(i), this)};
int length = Smi::cast(array->length())->value();
ElementsAccessor* accessor = array->GetElementsAccessor();
DCHECK(length % 2 == 0);
for (int i = 0; i < length; i += 2) {
DCHECK(accessor->HasElement(array, i));
DCHECK(accessor->HasElement(array, i + 1));
Handle<Object> argv[] = {value, accessor->Get(array, i),
accessor->Get(array, i + 1)};
*result = Execution::TryCall(this, promise_handle_fn, undefined, *result = Execution::TryCall(this, promise_handle_fn, undefined,
arraysize(argv), argv, maybe_exception); arraysize(argv), argv, maybe_exception);
// If execution is terminating, just bail out. // If execution is terminating, just bail out.
...@@ -3201,7 +3193,6 @@ void Isolate::PromiseReactionJob(Handle<PromiseReactionJobInfo> info, ...@@ -3201,7 +3193,6 @@ void Isolate::PromiseReactionJob(Handle<PromiseReactionJobInfo> info,
} }
} }
} else { } else {
Handle<Object> deferred(info->deferred(), this);
Handle<Object> argv[] = {value, tasks, deferred}; Handle<Object> argv[] = {value, tasks, deferred};
*result = Execution::TryCall(this, promise_handle_fn, undefined, *result = Execution::TryCall(this, promise_handle_fn, undefined,
arraysize(argv), argv, maybe_exception); arraysize(argv), argv, maybe_exception);
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
var AsyncFunctionNext; var AsyncFunctionNext;
var AsyncFunctionThrow; var AsyncFunctionThrow;
var CreateInternalPromiseCapability; var CreateInternalPromiseCapability;
var PerformPromiseThen;
var PromiseCreate; var PromiseCreate;
var PromiseNextMicrotaskID; var PromiseNextMicrotaskID;
var RejectPromise; var RejectPromise;
...@@ -24,7 +23,6 @@ utils.Import(function(from) { ...@@ -24,7 +23,6 @@ utils.Import(function(from) {
AsyncFunctionNext = from.AsyncFunctionNext; AsyncFunctionNext = from.AsyncFunctionNext;
AsyncFunctionThrow = from.AsyncFunctionThrow; AsyncFunctionThrow = from.AsyncFunctionThrow;
CreateInternalPromiseCapability = from.CreateInternalPromiseCapability; CreateInternalPromiseCapability = from.CreateInternalPromiseCapability;
PerformPromiseThen = from.PerformPromiseThen;
PromiseCreate = from.PromiseCreate; PromiseCreate = from.PromiseCreate;
RejectPromise = from.RejectPromise; RejectPromise = from.RejectPromise;
ResolvePromise = from.ResolvePromise; ResolvePromise = from.ResolvePromise;
...@@ -44,6 +42,7 @@ var promiseHasHandlerSymbol = ...@@ -44,6 +42,7 @@ var promiseHasHandlerSymbol =
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function PromiseCastResolved(value) { function PromiseCastResolved(value) {
// TODO(caitp): This is non spec compliant. See v8:5694.
if (%is_promise(value)) { if (%is_promise(value)) {
return value; return value;
} else { } else {
...@@ -106,7 +105,7 @@ function AsyncFunctionAwait(generator, awaited, outerPromise) { ...@@ -106,7 +105,7 @@ function AsyncFunctionAwait(generator, awaited, outerPromise) {
outerPromise); outerPromise);
} }
PerformPromiseThen(promise, onFulfilled, onRejected, throwawayCapability); %perform_promise_then(promise, onFulfilled, onRejected, throwawayCapability);
} }
// Called by the parser from the desugaring of 'await' when catch // Called by the parser from the desugaring of 'await' when catch
......
This diff is collapsed.
...@@ -104,7 +104,6 @@ void HeapObject::HeapObjectVerify() { ...@@ -104,7 +104,6 @@ void HeapObject::HeapObjectVerify() {
case JS_API_OBJECT_TYPE: case JS_API_OBJECT_TYPE:
case JS_SPECIAL_API_OBJECT_TYPE: case JS_SPECIAL_API_OBJECT_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE: case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_PROMISE_TYPE:
JSObject::cast(this)->JSObjectVerify(); JSObject::cast(this)->JSObjectVerify();
break; break;
case JS_GENERATOR_OBJECT_TYPE: case JS_GENERATOR_OBJECT_TYPE:
...@@ -205,6 +204,9 @@ void HeapObject::HeapObjectVerify() { ...@@ -205,6 +204,9 @@ void HeapObject::HeapObjectVerify() {
case JS_WEAK_SET_TYPE: case JS_WEAK_SET_TYPE:
JSWeakSet::cast(this)->JSWeakSetVerify(); JSWeakSet::cast(this)->JSWeakSetVerify();
break; break;
case JS_PROMISE_TYPE:
JSPromise::cast(this)->JSPromiseVerify();
break;
case JS_REGEXP_TYPE: case JS_REGEXP_TYPE:
JSRegExp::cast(this)->JSRegExpVerify(); JSRegExp::cast(this)->JSRegExpVerify();
break; break;
...@@ -884,6 +886,19 @@ void JSWeakSet::JSWeakSetVerify() { ...@@ -884,6 +886,19 @@ void JSWeakSet::JSWeakSetVerify() {
CHECK(table()->IsHashTable() || table()->IsUndefined(GetIsolate())); CHECK(table()->IsHashTable() || table()->IsUndefined(GetIsolate()));
} }
void JSPromise::JSPromiseVerify() {
CHECK(IsJSPromise());
JSObjectVerify();
Isolate* isolate = GetIsolate();
CHECK(result()->IsUndefined(isolate) || result()->IsObject());
CHECK(deferred()->IsUndefined(isolate) || deferred()->IsJSObject() ||
deferred()->IsFixedArray());
CHECK(fulfill_reactions()->IsUndefined(isolate) ||
fulfill_reactions()->IsCallable() ||
fulfill_reactions()->IsFixedArray());
CHECK(reject_reactions()->IsUndefined(isolate) ||
reject_reactions()->IsCallable() || reject_reactions()->IsFixedArray());
}
void JSRegExp::JSRegExpVerify() { void JSRegExp::JSRegExpVerify() {
JSObjectVerify(); JSObjectVerify();
...@@ -1011,8 +1026,8 @@ void PromiseReactionJobInfo::PromiseReactionJobInfoVerify() { ...@@ -1011,8 +1026,8 @@ void PromiseReactionJobInfo::PromiseReactionJobInfoVerify() {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
CHECK(IsPromiseReactionJobInfo()); CHECK(IsPromiseReactionJobInfo());
CHECK(value()->IsObject()); CHECK(value()->IsObject());
CHECK(tasks()->IsJSArray() || tasks()->IsCallable()); CHECK(tasks()->IsFixedArray() || tasks()->IsCallable());
CHECK(deferred()->IsJSObject() || deferred()->IsUndefined(isolate)); CHECK(deferred()->IsFixedArray() || deferred()->IsJSObject());
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()); CHECK(context()->IsContext());
......
...@@ -858,7 +858,6 @@ bool HeapObject::IsJSArrayBufferView() const { ...@@ -858,7 +858,6 @@ bool HeapObject::IsJSArrayBufferView() const {
TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE) TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE)
template <> inline bool Is<JSArray>(Object* obj) { template <> inline bool Is<JSArray>(Object* obj) {
return obj->IsJSArray(); return obj->IsJSArray();
} }
...@@ -2094,7 +2093,7 @@ int JSObject::GetHeaderSize(InstanceType type) { ...@@ -2094,7 +2093,7 @@ int JSObject::GetHeaderSize(InstanceType type) {
case JS_WEAK_SET_TYPE: case JS_WEAK_SET_TYPE:
return JSWeakSet::kSize; return JSWeakSet::kSize;
case JS_PROMISE_TYPE: case JS_PROMISE_TYPE:
return JSObject::kHeaderSize; return JSPromise::kSize;
case JS_REGEXP_TYPE: case JS_REGEXP_TYPE:
return JSRegExp::kSize; return JSRegExp::kSize;
case JS_CONTEXT_EXTENSION_OBJECT_TYPE: case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
...@@ -3323,6 +3322,7 @@ CAST_ACCESSOR(JSObject) ...@@ -3323,6 +3322,7 @@ CAST_ACCESSOR(JSObject)
CAST_ACCESSOR(JSProxy) CAST_ACCESSOR(JSProxy)
CAST_ACCESSOR(JSReceiver) CAST_ACCESSOR(JSReceiver)
CAST_ACCESSOR(JSRegExp) CAST_ACCESSOR(JSRegExp)
CAST_ACCESSOR(JSPromise)
CAST_ACCESSOR(JSSet) CAST_ACCESSOR(JSSet)
CAST_ACCESSOR(JSSetIterator) CAST_ACCESSOR(JSSetIterator)
CAST_ACCESSOR(JSStringIterator) CAST_ACCESSOR(JSStringIterator)
...@@ -7095,6 +7095,11 @@ void JSTypedArray::set_length(Object* value, WriteBarrierMode mode) { ...@@ -7095,6 +7095,11 @@ void JSTypedArray::set_length(Object* value, WriteBarrierMode mode) {
ACCESSORS(JSTypedArray, raw_length, Object, kLengthOffset) ACCESSORS(JSTypedArray, raw_length, Object, kLengthOffset)
#endif #endif
SMI_ACCESSORS(JSPromise, status, kStatusOffset)
ACCESSORS(JSPromise, result, Object, kResultOffset)
ACCESSORS(JSPromise, deferred, Object, kDeferredOffset)
ACCESSORS(JSPromise, fulfill_reactions, Object, kFulfillReactionsOffset)
ACCESSORS(JSPromise, reject_reactions, Object, kRejectReactionsOffset)
ACCESSORS(JSRegExp, data, Object, kDataOffset) ACCESSORS(JSRegExp, data, Object, kDataOffset)
ACCESSORS(JSRegExp, flags, Object, kFlagsOffset) ACCESSORS(JSRegExp, flags, Object, kFlagsOffset)
......
...@@ -150,11 +150,13 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT ...@@ -150,11 +150,13 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
case JS_SPECIAL_API_OBJECT_TYPE: case JS_SPECIAL_API_OBJECT_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE: case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_GENERATOR_OBJECT_TYPE: case JS_GENERATOR_OBJECT_TYPE:
case JS_PROMISE_TYPE:
case JS_ARGUMENTS_TYPE: case JS_ARGUMENTS_TYPE:
case JS_ERROR_TYPE: case JS_ERROR_TYPE:
JSObject::cast(this)->JSObjectPrint(os); JSObject::cast(this)->JSObjectPrint(os);
break; break;
case JS_PROMISE_TYPE:
JSPromise::cast(this)->JSPromisePrint(os);
break;
case JS_ARRAY_TYPE: case JS_ARRAY_TYPE:
JSArray::cast(this)->JSArrayPrint(os); JSArray::cast(this)->JSArrayPrint(os);
break; break;
...@@ -542,6 +544,14 @@ void JSArray::JSArrayPrint(std::ostream& os) { // NOLINT ...@@ -542,6 +544,14 @@ void JSArray::JSArrayPrint(std::ostream& os) { // NOLINT
JSObjectPrintBody(os, this); JSObjectPrintBody(os, this);
} }
void JSPromise::JSPromisePrint(std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, this, "JSPromise");
os << "\n - status = " << JSPromise::Status(status());
os << "\n - result = " << Brief(result());
os << "\n - deferreds = " << Brief(deferred());
os << "\n - fulfill_reactions = " << Brief(fulfill_reactions());
os << "\n - reject_reactions = " << Brief(reject_reactions());
}
void JSRegExp::JSRegExpPrint(std::ostream& os) { // NOLINT void JSRegExp::JSRegExpPrint(std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, this, "JSRegExp"); JSObjectPrintHeader(os, this, "JSRegExp");
......
...@@ -16447,6 +16447,19 @@ class StringSharedKey : public HashTableKey { ...@@ -16447,6 +16447,19 @@ class StringSharedKey : public HashTableKey {
int scope_position_; int scope_position_;
}; };
// static
const char* JSPromise::Status(int status) {
switch (status) {
case kPromiseFulfilled:
return "resolved";
case kPromisePending:
return "pending";
case kPromiseRejected:
return "rejected";
}
UNREACHABLE();
return NULL;
}
namespace { namespace {
......
...@@ -8895,6 +8895,41 @@ class JSMessageObject: public JSObject { ...@@ -8895,6 +8895,41 @@ class JSMessageObject: public JSObject {
kSize> BodyDescriptor; kSize> BodyDescriptor;
}; };
class JSPromise : public JSObject {
public:
DECL_INT_ACCESSORS(status)
DECL_ACCESSORS(result, Object)
// There are 3 possible states for these fields --
// 1) Undefined -- This is the zero state when there is no callback
// or deferred registered.
// 2) Object -- There is a single Callable directly attached to the
// fulfill_reactions, reject_reactions and the deferred JSObject is
// directly attached to the deferred field.
// 3) FixedArray -- There is more than one callback and deferred
// attached to a FixedArray.
DECL_ACCESSORS(deferred, Object)
DECL_ACCESSORS(fulfill_reactions, Object)
DECL_ACCESSORS(reject_reactions, Object)
static const char* Status(int status);
DECLARE_CAST(JSPromise)
// Dispatched behavior.
DECLARE_PRINTER(JSPromise)
DECLARE_VERIFIER(JSPromise)
// Layout description.
static const int kStatusOffset = JSObject::kHeaderSize;
static const int kResultOffset = kStatusOffset + kPointerSize;
static const int kDeferredOffset = kResultOffset + kPointerSize;
static const int kFulfillReactionsOffset = kDeferredOffset + kPointerSize;
static const int kRejectReactionsOffset =
kFulfillReactionsOffset + kPointerSize;
static const int kSize = kRejectReactionsOffset + kPointerSize;
};
// Regular expressions // Regular expressions
// The regular expression holds a single reference to a FixedArray in // The regular expression holds a single reference to a FixedArray in
// the kDataOffset field. // the kDataOffset field.
......
...@@ -136,14 +136,6 @@ static Handle<Object> DebugGetProperty(LookupIterator* it, ...@@ -136,14 +136,6 @@ static Handle<Object> DebugGetProperty(LookupIterator* it,
return it->isolate()->factory()->undefined_value(); return it->isolate()->factory()->undefined_value();
} }
static Handle<Object> DebugGetProperty(Handle<Object> object,
Handle<Name> name) {
LookupIterator it(object, name);
return DebugGetProperty(&it);
}
template <class IteratorType> template <class IteratorType>
static MaybeHandle<JSArray> GetIteratorInternalProperties( static MaybeHandle<JSArray> GetIteratorInternalProperties(
Isolate* isolate, Handle<IteratorType> object) { Isolate* isolate, Handle<IteratorType> object) {
...@@ -248,24 +240,8 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate, ...@@ -248,24 +240,8 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
result->set(5, generator->receiver()); result->set(5, generator->receiver());
return factory->NewJSArrayWithElements(result); return factory->NewJSArrayWithElements(result);
} else if (object->IsJSPromise()) { } else if (object->IsJSPromise()) {
Handle<JSObject> promise = Handle<JSObject>::cast(object); Handle<JSPromise> promise = Handle<JSPromise>::cast(object);
const char* status = JSPromise::Status(promise->status());
Handle<Object> status_obj =
DebugGetProperty(promise, isolate->factory()->promise_state_symbol());
CHECK(status_obj->IsSmi());
const char* status = "rejected";
int status_val = Handle<Smi>::cast(status_obj)->value();
switch (status_val) {
case kPromiseFulfilled:
status = "resolved";
break;
case kPromisePending:
status = "pending";
break;
default:
DCHECK_EQ(kPromiseRejected, status_val);
}
Handle<FixedArray> result = factory->NewFixedArray(2 * 2); Handle<FixedArray> result = factory->NewFixedArray(2 * 2);
Handle<String> promise_status = Handle<String> promise_status =
factory->NewStringFromAsciiChecked("[[PromiseStatus]]"); factory->NewStringFromAsciiChecked("[[PromiseStatus]]");
...@@ -273,8 +249,7 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate, ...@@ -273,8 +249,7 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
Handle<String> status_str = factory->NewStringFromAsciiChecked(status); Handle<String> status_str = factory->NewStringFromAsciiChecked(status);
result->set(1, *status_str); result->set(1, *status_str);
Handle<Object> value_obj = Handle<Object> value_obj(promise->result(), isolate);
DebugGetProperty(promise, isolate->factory()->promise_result_symbol());
Handle<String> promise_value = Handle<String> promise_value =
factory->NewStringFromAsciiChecked("[[PromiseValue]]"); factory->NewStringFromAsciiChecked("[[PromiseValue]]");
result->set(2, *promise_value); result->set(2, *promise_value);
......
// 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/runtime/runtime-utils.h" #include "src/runtime/runtime-utils.h"
#include "src/debug/debug.h" #include "src/debug/debug.h"
...@@ -66,10 +65,17 @@ void EnqueuePromiseReactionJob(Isolate* isolate, Handle<Object> value, ...@@ -66,10 +65,17 @@ void EnqueuePromiseReactionJob(Isolate* isolate, Handle<Object> value,
Handle<Object> debug_name = isolate->factory()->undefined_value(); Handle<Object> debug_name = isolate->factory()->undefined_value();
if (isolate->debug()->is_active()) { if (isolate->debug()->is_active()) {
MaybeHandle<Object> maybe_result; MaybeHandle<Object> maybe_result;
Handle<Object> argv[] = {deferred, status}; Handle<Object> deferred_obj(deferred);
if (deferred->IsFixedArray()) {
deferred_obj = isolate->factory()->undefined_value();
}
Handle<Object> argv[] = {deferred_obj, status};
maybe_result = Execution::TryCall( maybe_result = Execution::TryCall(
isolate, isolate->promise_debug_get_info(), isolate, isolate->promise_debug_get_info(),
isolate->factory()->undefined_value(), arraysize(argv), argv); isolate->factory()->undefined_value(), arraysize(argv), argv);
Handle<Object> result; Handle<Object> result;
if ((maybe_result).ToHandle(&result)) { if ((maybe_result).ToHandle(&result)) {
CHECK(result->IsJSArray()); CHECK(result->IsJSArray());
...@@ -88,42 +94,50 @@ void EnqueuePromiseReactionJob(Isolate* isolate, Handle<Object> value, ...@@ -88,42 +94,50 @@ void EnqueuePromiseReactionJob(Isolate* isolate, Handle<Object> value,
isolate->EnqueueMicrotask(info); isolate->EnqueueMicrotask(info);
} }
void PromiseFulfill(Isolate* isolate, Handle<JSReceiver> promise, void PromiseSet(Handle<JSPromise> promise, int status, Handle<Object> result) {
Handle<Smi> status, Handle<Object> value, promise->set_status(status);
Handle<Symbol> reaction) { promise->set_result(*result);
Handle<Object> tasks = JSReceiver::GetDataProperty(promise, reaction); // TODO(gsathya): reset reactions?
if (!tasks->IsUndefined(isolate)) { }
Handle<Object> deferred = JSReceiver::GetDataProperty(
promise, isolate->factory()->promise_deferred_reaction_symbol()); void PromiseFulfill(Isolate* isolate, Handle<JSPromise> promise,
Handle<Smi> status, Handle<Object> value) {
// Check if there are any callbacks.
if (!promise->deferred()->IsUndefined(isolate)) {
Handle<Object> tasks((status->value() == kPromiseFulfilled)
? promise->fulfill_reactions()
: promise->reject_reactions(),
isolate);
Handle<Object> deferred(promise->deferred(), isolate);
EnqueuePromiseReactionJob(isolate, value, tasks, deferred, status); EnqueuePromiseReactionJob(isolate, value, tasks, deferred, status);
} }
PromiseSet(promise, status->value(), value);
} }
} // namespace } // namespace
RUNTIME_FUNCTION(Runtime_PromiseReject) { RUNTIME_FUNCTION(Runtime_PromiseReject) {
DCHECK(args.length() == 3); DCHECK(args.length() == 3);
HandleScope scope(isolate); HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, promise, 0); CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1); CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1);
CONVERT_BOOLEAN_ARG_CHECKED(debug_event, 2); CONVERT_BOOLEAN_ARG_CHECKED(debug_event, 2);
PromiseRejectEvent(isolate, promise, promise, reason, debug_event); PromiseRejectEvent(isolate, promise, promise, reason, debug_event);
Handle<Smi> status = handle(Smi::FromInt(kPromiseRejected), isolate); Handle<Smi> status(Smi::FromInt(kPromiseRejected), isolate);
Handle<Symbol> reaction = PromiseFulfill(isolate, promise, status, reason);
isolate->factory()->promise_reject_reactions_symbol();
PromiseFulfill(isolate, promise, status, reason, reaction);
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
RUNTIME_FUNCTION(Runtime_PromiseFulfill) { RUNTIME_FUNCTION(Runtime_PromiseFulfill) {
DCHECK(args.length() == 4); DCHECK(args.length() == 3);
HandleScope scope(isolate); HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, promise, 0); CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
CONVERT_ARG_HANDLE_CHECKED(Smi, status, 1); CONVERT_ARG_HANDLE_CHECKED(Smi, status, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
CONVERT_ARG_HANDLE_CHECKED(Symbol, reaction, 3); PromiseFulfill(isolate, promise, status, value);
PromiseFulfill(isolate, promise, status, value, reaction);
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
...@@ -192,6 +206,7 @@ RUNTIME_FUNCTION(Runtime_RunMicrotasks) { ...@@ -192,6 +206,7 @@ RUNTIME_FUNCTION(Runtime_RunMicrotasks) {
RUNTIME_FUNCTION(Runtime_CreateResolvingFunctions) { RUNTIME_FUNCTION(Runtime_CreateResolvingFunctions) {
HandleScope scope(isolate); HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
DCHECK(args.length() == 1);
Handle<JSFunction> resolve, reject; Handle<JSFunction> resolve, reject;
PromiseUtils::CreateResolvingFunctions( PromiseUtils::CreateResolvingFunctions(
...@@ -204,5 +219,58 @@ RUNTIME_FUNCTION(Runtime_CreateResolvingFunctions) { ...@@ -204,5 +219,58 @@ RUNTIME_FUNCTION(Runtime_CreateResolvingFunctions) {
return *result; return *result;
} }
RUNTIME_FUNCTION(Runtime_PromiseStatus) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
return Smi::FromInt(promise->status());
}
RUNTIME_FUNCTION(Runtime_PromiseResult) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
return promise->result();
}
RUNTIME_FUNCTION(Runtime_PromiseDeferred) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
Handle<Object> deferred(promise->deferred(), isolate);
if (deferred->IsUndefined(isolate)) {
return isolate->heap()->undefined_value();
}
if (deferred->IsJSObject()) {
return *deferred;
}
DCHECK(deferred->IsFixedArray());
return *isolate->factory()->NewJSArrayWithElements(
Handle<FixedArray>::cast(deferred));
}
RUNTIME_FUNCTION(Runtime_PromiseRejectReactions) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
Handle<Object> reject_reactions(promise->reject_reactions(), isolate);
if (reject_reactions->IsUndefined(isolate)) {
return isolate->heap()->undefined_value();
}
if (reject_reactions->IsJSObject()) {
return *reject_reactions;
}
DCHECK(reject_reactions->IsFixedArray());
return *isolate->factory()->NewJSArrayWithElements(
Handle<FixedArray>::cast(reject_reactions));
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -304,10 +304,14 @@ namespace internal { ...@@ -304,10 +304,14 @@ namespace internal {
F(NewSyntaxError, 2, 1) \ F(NewSyntaxError, 2, 1) \
F(NewTypeError, 2, 1) \ F(NewTypeError, 2, 1) \
F(OrdinaryHasInstance, 2, 1) \ F(OrdinaryHasInstance, 2, 1) \
F(PromiseDeferred, 1, 1) \
F(PromiseReject, 3, 1) \ F(PromiseReject, 3, 1) \
F(PromiseFulfill, 4, 1) \ F(PromiseFulfill, 3, 1) \
F(PromiseRejectEventFromStack, 2, 1) \ F(PromiseRejectEventFromStack, 2, 1) \
F(PromiseRejectReactions, 1, 1) \
F(PromiseRevokeReject, 1, 1) \ F(PromiseRevokeReject, 1, 1) \
F(PromiseResult, 1, 1) \
F(PromiseStatus, 1, 1) \
F(PromoteScheduledException, 0, 1) \ F(PromoteScheduledException, 0, 1) \
F(ReThrow, 1, 1) \ F(ReThrow, 1, 1) \
F(RunMicrotasks, 0, 1) \ F(RunMicrotasks, 0, 1) \
......
...@@ -1099,10 +1099,8 @@ TEST(SubclassPromiseBuiltin) { ...@@ -1099,10 +1099,8 @@ TEST(SubclassPromiseBuiltin) {
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
const int first_field = 5;
TestSubclassBuiltin("A1", JS_PROMISE_TYPE, "Promise", TestSubclassBuiltin("A1", JS_PROMISE_TYPE, "Promise",
"function(resolve, reject) { resolve('ok'); }", "function(resolve, reject) { resolve('ok'); }");
first_field);
} }
......
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