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