Chromium Code Reviews| Index: src/builtins/builtins-promise.cc |
| diff --git a/src/builtins/builtins-promise.cc b/src/builtins/builtins-promise.cc |
| index 323bfea5b5a74268d4b4665b8de7b46a0516cbcf..d3de4ce5cc1ca68ddd69fe61696cc256738c2fe5 100644 |
| --- a/src/builtins/builtins-promise.cc |
| +++ b/src/builtins/builtins-promise.cc |
| @@ -190,7 +190,8 @@ Node* PromiseBuiltinsAssembler::CreatePromiseGetCapabilitiesExecutorContext( |
| } |
| Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver( |
| - Node* context, Node* value, MessageTemplate::Template msg_template) { |
| + Node* context, Node* value, MessageTemplate::Template msg_template, |
| + const char* method_name) { |
| Label out(this), throw_exception(this, Label::kDeferred); |
| Variable var_value_map(this, MachineRepresentation::kTagged); |
| @@ -205,8 +206,15 @@ Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver( |
| // The {value} is not a compatible receiver for this method. |
| Bind(&throw_exception); |
| { |
| + Isolate* isolate = this->isolate(); |
|
adamk
2017/01/04 19:19:21
I don't think you need this, can just use "isolate
gsathya
2017/01/04 19:37:17
Done.
|
| + Node* method; |
|
adamk
2017/01/04 19:19:21
Node* const for consistency.
gsathya
2017/01/04 19:37:17
Done.
|
| + method = method_name == NULL |
|
adamk
2017/01/04 19:19:21
s/NULL/nullptr/
And you can merge this with the d
gsathya
2017/01/04 19:37:17
Done.
|
| + ? UndefinedConstant() |
| + : HeapConstant(isolate->factory()->NewStringFromAsciiChecked( |
| + method_name)); |
| + |
| Node* const message_id = SmiConstant(msg_template); |
| - CallRuntime(Runtime::kThrowTypeError, context, message_id); |
| + CallRuntime(Runtime::kThrowTypeError, context, message_id, method); |
| var_value_map.Bind(UndefinedConstant()); |
| Goto(&out); // Never reached. |
| } |
| @@ -565,11 +573,25 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen( |
| void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, |
| Label* if_isunmodified, |
| Label* if_ismodified) { |
| - // TODO(gsathya): Assert if promise is receiver |
| - Node* const map = LoadMap(promise); |
| Node* const native_context = LoadNativeContext(context); |
| Node* const promise_fun = |
| LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
| + BranchIfFastPath(native_context, promise_fun, promise, if_isunmodified, |
| + if_ismodified); |
| +} |
| + |
| +void PromiseBuiltinsAssembler::BranchIfFastPath(Node* native_context, |
| + Node* promise_fun, |
| + Node* promise, |
| + Label* if_isunmodified, |
| + Label* if_ismodified) { |
| + CSA_ASSERT(this, IsNativeContext(native_context)); |
| + CSA_ASSERT(this, |
| + WordEqual(promise_fun, |
| + LoadContextElement(native_context, |
| + Context::PROMISE_FUNCTION_INDEX))); |
| + |
| + Node* const map = LoadMap(promise); |
| Node* const initial_map = |
| LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); |
| Node* const has_initialmap = WordEqual(map, initial_map); |
| @@ -610,7 +632,11 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context, |
| GotoUnless(IsJSReceiver(result), &fulfill); |
| Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred); |
| - BranchIfFastPath(context, result, &if_nativepromise, &if_notnativepromise); |
| + Node* const native_context = LoadNativeContext(context); |
| + Node* const promise_fun = |
| + LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
| + BranchIfFastPath(native_context, promise_fun, result, &if_nativepromise, |
| + &if_notnativepromise); |
| // Resolution is a native promise and if it's already resolved or |
| // rejected, shortcircuit the resolution procedure by directly |
| @@ -629,7 +655,6 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context, |
| // TODO(gsathya): Use a marker here instead of the actual then |
| // callback, and check for the marker in PromiseResolveThenableJob |
| // and perform PromiseThen. |
| - Node* const native_context = LoadNativeContext(context); |
| Node* const then = |
| LoadContextElement(native_context, Context::PROMISE_THEN_INDEX); |
| var_then.Bind(then); |
| @@ -1135,6 +1160,103 @@ TF_BUILTIN(PromiseCatch, PromiseBuiltinsAssembler) { |
| } |
| } |
| +TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) { |
| + // 1. Let C be the this value. |
| + Node* receiver = Parameter(0); |
| + Node* value = Parameter(1); |
| + Node* context = Parameter(4); |
| + Isolate* isolate = this->isolate(); |
| + |
| + // 2. If Type(C) is not Object, throw a TypeError exception. |
| + ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject, |
| + "PromiseResolve"); |
| + |
| + Label if_valueisnativepromise(this), if_valueisnotnativepromise(this), |
| + if_valueisnotpromise(this); |
| + |
| + // 3.If IsPromise(x) is true, then |
| + GotoIf(TaggedIsSmi(value), &if_valueisnotpromise); |
| + |
| + // This shortcircuits the constructor lookups. |
| + GotoUnless(HasInstanceType(value, JS_PROMISE_TYPE), &if_valueisnotpromise); |
| + |
| + // This adds a fast path as non-subclassed native promises don't have |
| + // an observable constructor lookup. |
| + Node* const native_context = LoadNativeContext(context); |
| + Node* const promise_fun = |
| + LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
| + BranchIfFastPath(native_context, promise_fun, value, &if_valueisnativepromise, |
| + &if_valueisnotnativepromise); |
| + |
| + Bind(&if_valueisnativepromise); |
| + { |
| + GotoUnless(WordEqual(promise_fun, receiver), &if_valueisnotnativepromise); |
| + Return(value); |
| + } |
| + |
| + // At this point, value or/and receiver are not native promises, but |
| + // they could be of the same subclass. |
| + Bind(&if_valueisnotnativepromise); |
| + { |
| + // 3.a Let xConstructor be ? Get(x, "constructor"). |
| + // The constructor lookup is observable. |
| + Node* const constructor_str = |
| + HeapConstant(isolate->factory()->constructor_string()); |
| + Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
| + Node* const constructor = |
| + CallStub(getproperty_callable, context, value, constructor_str); |
| + |
| + // 3.b If SameValue(xConstructor, C) is true, return x. |
| + GotoUnless(SameValue(constructor, receiver, context), |
| + &if_valueisnotpromise); |
| + |
| + Return(value); |
| + } |
| + |
| + Bind(&if_valueisnotpromise); |
| + { |
| + Label if_nativepromise(this), if_notnativepromise(this); |
| + BranchIfFastPath(context, receiver, &if_nativepromise, |
| + &if_notnativepromise); |
| + |
| + // This adds a fast path for native promises that don't need to |
| + // create NewPromiseCapability. |
| + Bind(&if_nativepromise); |
| + { |
| + Label do_resolve(this); |
| + |
| + Node* const result = AllocateJSPromise(context); |
| + PromiseInit(result); |
| + |
| + GotoUnless(IsPromiseHookEnabled(), &do_resolve); |
| + CallRuntime(Runtime::kPromiseHookInit, context, result, |
| + UndefinedConstant()); |
| + Goto(&do_resolve); |
| + |
| + Bind(&do_resolve); |
| + InternalResolvePromise(context, result, value); |
| + Return(result); |
| + } |
| + |
| + Bind(&if_notnativepromise); |
| + { |
| + // 4. Let promiseCapability be ? NewPromiseCapability(C). |
| + Node* const capability = NewPromiseCapability(context, receiver); |
| + |
| + // 5. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »). |
| + Callable call_callable = CodeFactory::Call(isolate); |
| + Node* const resolve = |
| + LoadObjectField(capability, JSPromiseCapability::kResolveOffset); |
| + CallJS(call_callable, context, resolve, UndefinedConstant(), value); |
| + |
| + // 6. Return promiseCapability.[[Promise]]. |
| + Node* const result = |
| + LoadObjectField(capability, JSPromiseCapability::kPromiseOffset); |
| + Return(result); |
| + } |
| + } |
| +} |
| + |
| TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) { |
| Node* const resolve = Parameter(1); |
| Node* const reject = Parameter(2); |