Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Side by Side Diff: src/builtins/builtins-promise.cc

Issue 2592933004: [promises] Move Promise.resolve to TF (Closed)
Patch Set: fix rebase Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins-promise.h ('k') | src/js/promise.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/builtins/builtins-promise.h" 5 #include "src/builtins/builtins-promise.h"
6 #include "src/builtins/builtins-constructor.h" 6 #include "src/builtins/builtins-constructor.h"
7 #include "src/builtins/builtins-utils.h" 7 #include "src/builtins/builtins-utils.h"
8 #include "src/builtins/builtins.h" 8 #include "src/builtins/builtins.h"
9 #include "src/code-factory.h" 9 #include "src/code-factory.h"
10 #include "src/code-stub-assembler.h" 10 #include "src/code-stub-assembler.h"
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 Node* promise_capability, Node* native_context) { 225 Node* promise_capability, Node* native_context) {
226 int kContextLength = GetPromiseCapabilityExecutor::kContextLength; 226 int kContextLength = GetPromiseCapabilityExecutor::kContextLength;
227 Node* context = CreatePromiseContext(native_context, kContextLength); 227 Node* context = CreatePromiseContext(native_context, kContextLength);
228 StoreContextElementNoWriteBarrier( 228 StoreContextElementNoWriteBarrier(
229 context, GetPromiseCapabilityExecutor::kCapabilitySlot, 229 context, GetPromiseCapabilityExecutor::kCapabilitySlot,
230 promise_capability); 230 promise_capability);
231 return context; 231 return context;
232 } 232 }
233 233
234 Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver( 234 Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver(
235 Node* context, Node* value, MessageTemplate::Template msg_template) { 235 Node* context, Node* value, MessageTemplate::Template msg_template,
236 const char* method_name) {
236 Label out(this), throw_exception(this, Label::kDeferred); 237 Label out(this), throw_exception(this, Label::kDeferred);
237 Variable var_value_map(this, MachineRepresentation::kTagged); 238 Variable var_value_map(this, MachineRepresentation::kTagged);
238 239
239 GotoIf(TaggedIsSmi(value), &throw_exception); 240 GotoIf(TaggedIsSmi(value), &throw_exception);
240 241
241 // Load the instance type of the {value}. 242 // Load the instance type of the {value}.
242 var_value_map.Bind(LoadMap(value)); 243 var_value_map.Bind(LoadMap(value));
243 Node* const value_instance_type = LoadMapInstanceType(var_value_map.value()); 244 Node* const value_instance_type = LoadMapInstanceType(var_value_map.value());
244 245
245 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception); 246 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception);
246 247
247 // The {value} is not a compatible receiver for this method. 248 // The {value} is not a compatible receiver for this method.
248 Bind(&throw_exception); 249 Bind(&throw_exception);
249 { 250 {
251 Node* const method =
252 method_name == nullptr
253 ? UndefinedConstant()
254 : HeapConstant(
255 isolate()->factory()->NewStringFromAsciiChecked(method_name));
250 Node* const message_id = SmiConstant(msg_template); 256 Node* const message_id = SmiConstant(msg_template);
251 CallRuntime(Runtime::kThrowTypeError, context, message_id); 257 CallRuntime(Runtime::kThrowTypeError, context, message_id, method);
252 var_value_map.Bind(UndefinedConstant()); 258 var_value_map.Bind(UndefinedConstant());
253 Goto(&out); // Never reached. 259 Goto(&out); // Never reached.
254 } 260 }
255 261
256 Bind(&out); 262 Bind(&out);
257 return var_value_map.value(); 263 return var_value_map.value();
258 } 264 }
259 265
260 Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) { 266 Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) {
261 Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset); 267 Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 } 606 }
601 607
602 // Promise fast path implementations rely on unmodified JSPromise instances. 608 // Promise fast path implementations rely on unmodified JSPromise instances.
603 // We use a fairly coarse granularity for this and simply check whether both 609 // We use a fairly coarse granularity for this and simply check whether both
604 // the promise itself is unmodified (i.e. its map has not changed) and its 610 // the promise itself is unmodified (i.e. its map has not changed) and its
605 // prototype is unmodified. 611 // prototype is unmodified.
606 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp 612 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp
607 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, 613 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise,
608 Label* if_isunmodified, 614 Label* if_isunmodified,
609 Label* if_ismodified) { 615 Label* if_ismodified) {
610 // TODO(gsathya): Assert if promise is receiver
611 Node* const map = LoadMap(promise);
612 Node* const native_context = LoadNativeContext(context); 616 Node* const native_context = LoadNativeContext(context);
613 Node* const promise_fun = 617 Node* const promise_fun =
614 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); 618 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
619 BranchIfFastPath(native_context, promise_fun, promise, if_isunmodified,
620 if_ismodified);
621 }
622
623 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* native_context,
624 Node* promise_fun,
625 Node* promise,
626 Label* if_isunmodified,
627 Label* if_ismodified) {
628 CSA_ASSERT(this, IsNativeContext(native_context));
629 CSA_ASSERT(this,
630 WordEqual(promise_fun,
631 LoadContextElement(native_context,
632 Context::PROMISE_FUNCTION_INDEX)));
633
634 Node* const map = LoadMap(promise);
615 Node* const initial_map = 635 Node* const initial_map =
616 LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); 636 LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
617 Node* const has_initialmap = WordEqual(map, initial_map); 637 Node* const has_initialmap = WordEqual(map, initial_map);
618 638
619 GotoUnless(has_initialmap, if_ismodified); 639 GotoUnless(has_initialmap, if_ismodified);
620 640
621 Node* const initial_proto_initial_map = 641 Node* const initial_proto_initial_map =
622 LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX); 642 LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX);
623 Node* const proto_map = LoadMap(LoadMapPrototype(map)); 643 Node* const proto_map = LoadMap(LoadMapPrototype(map));
624 Node* const proto_has_initialmap = 644 Node* const proto_has_initialmap =
(...skipping 20 matching lines...) Expand all
645 665
646 Bind(&cycle_check); 666 Bind(&cycle_check);
647 // 6. If SameValue(resolution, promise) is true, then 667 // 6. If SameValue(resolution, promise) is true, then
648 GotoIf(SameValue(promise, result, context), &if_cycle); 668 GotoIf(SameValue(promise, result, context), &if_cycle);
649 669
650 // 7. If Type(resolution) is not Object, then 670 // 7. If Type(resolution) is not Object, then
651 GotoIf(TaggedIsSmi(result), &fulfill); 671 GotoIf(TaggedIsSmi(result), &fulfill);
652 GotoUnless(IsJSReceiver(result), &fulfill); 672 GotoUnless(IsJSReceiver(result), &fulfill);
653 673
654 Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred); 674 Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred);
655 BranchIfFastPath(context, result, &if_nativepromise, &if_notnativepromise); 675 Node* const native_context = LoadNativeContext(context);
676 Node* const promise_fun =
677 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
678 BranchIfFastPath(native_context, promise_fun, result, &if_nativepromise,
679 &if_notnativepromise);
656 680
657 // Resolution is a native promise and if it's already resolved or 681 // Resolution is a native promise and if it's already resolved or
658 // rejected, shortcircuit the resolution procedure by directly 682 // rejected, shortcircuit the resolution procedure by directly
659 // reusing the value from the promise. 683 // reusing the value from the promise.
660 Bind(&if_nativepromise); 684 Bind(&if_nativepromise);
661 { 685 {
662 Node* const thenable_status = 686 Node* const thenable_status =
663 LoadObjectField(result, JSPromise::kStatusOffset); 687 LoadObjectField(result, JSPromise::kStatusOffset);
664 Node* const thenable_value = 688 Node* const thenable_value =
665 LoadObjectField(result, JSPromise::kResultOffset); 689 LoadObjectField(result, JSPromise::kResultOffset);
666 690
667 Label if_isnotpending(this); 691 Label if_isnotpending(this);
668 GotoUnless(SmiEqual(SmiConstant(v8::Promise::kPending), thenable_status), 692 GotoUnless(SmiEqual(SmiConstant(v8::Promise::kPending), thenable_status),
669 &if_isnotpending); 693 &if_isnotpending);
670 694
671 // TODO(gsathya): Use a marker here instead of the actual then 695 // TODO(gsathya): Use a marker here instead of the actual then
672 // callback, and check for the marker in PromiseResolveThenableJob 696 // callback, and check for the marker in PromiseResolveThenableJob
673 // and perform PromiseThen. 697 // and perform PromiseThen.
674 Node* const native_context = LoadNativeContext(context);
675 Node* const then = 698 Node* const then =
676 LoadContextElement(native_context, Context::PROMISE_THEN_INDEX); 699 LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
677 var_then.Bind(then); 700 var_then.Bind(then);
678 Goto(&do_enqueue); 701 Goto(&do_enqueue);
679 702
680 Bind(&if_isnotpending); 703 Bind(&if_isnotpending);
681 { 704 {
682 Label if_fulfilled(this), if_rejected(this); 705 Label if_fulfilled(this), if_rejected(this);
683 Branch(SmiEqual(SmiConstant(v8::Promise::kFulfilled), thenable_status), 706 Branch(SmiEqual(SmiConstant(v8::Promise::kFulfilled), thenable_status),
684 &if_fulfilled, &if_rejected); 707 &if_fulfilled, &if_rejected);
(...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after
1200 Callable getproperty_callable = CodeFactory::GetProperty(isolate); 1223 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
1201 Node* const then = 1224 Node* const then =
1202 CallStub(getproperty_callable, context, promise, then_str); 1225 CallStub(getproperty_callable, context, promise, then_str);
1203 Callable call_callable = CodeFactory::Call(isolate); 1226 Callable call_callable = CodeFactory::Call(isolate);
1204 Node* const result = 1227 Node* const result =
1205 CallJS(call_callable, context, then, promise, on_resolve, on_reject); 1228 CallJS(call_callable, context, then, promise, on_resolve, on_reject);
1206 Return(result); 1229 Return(result);
1207 } 1230 }
1208 } 1231 }
1209 1232
1233 TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
1234 // 1. Let C be the this value.
1235 Node* receiver = Parameter(0);
1236 Node* value = Parameter(1);
1237 Node* context = Parameter(4);
1238 Isolate* isolate = this->isolate();
1239
1240 // 2. If Type(C) is not Object, throw a TypeError exception.
1241 ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1242 "PromiseResolve");
1243
1244 Label if_valueisnativepromise(this), if_valueisnotnativepromise(this),
1245 if_valueisnotpromise(this);
1246
1247 // 3.If IsPromise(x) is true, then
1248 GotoIf(TaggedIsSmi(value), &if_valueisnotpromise);
1249
1250 // This shortcircuits the constructor lookups.
1251 GotoUnless(HasInstanceType(value, JS_PROMISE_TYPE), &if_valueisnotpromise);
1252
1253 // This adds a fast path as non-subclassed native promises don't have
1254 // an observable constructor lookup.
1255 Node* const native_context = LoadNativeContext(context);
1256 Node* const promise_fun =
1257 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1258 BranchIfFastPath(native_context, promise_fun, value, &if_valueisnativepromise,
1259 &if_valueisnotnativepromise);
1260
1261 Bind(&if_valueisnativepromise);
1262 {
1263 GotoUnless(WordEqual(promise_fun, receiver), &if_valueisnotnativepromise);
1264 Return(value);
1265 }
1266
1267 // At this point, value or/and receiver are not native promises, but
1268 // they could be of the same subclass.
1269 Bind(&if_valueisnotnativepromise);
1270 {
1271 // 3.a Let xConstructor be ? Get(x, "constructor").
1272 // The constructor lookup is observable.
1273 Node* const constructor_str =
1274 HeapConstant(isolate->factory()->constructor_string());
1275 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
1276 Node* const constructor =
1277 CallStub(getproperty_callable, context, value, constructor_str);
1278
1279 // 3.b If SameValue(xConstructor, C) is true, return x.
1280 GotoUnless(SameValue(constructor, receiver, context),
1281 &if_valueisnotpromise);
1282
1283 Return(value);
1284 }
1285
1286 Bind(&if_valueisnotpromise);
1287 {
1288 Label if_nativepromise(this), if_notnativepromise(this);
1289 BranchIfFastPath(context, receiver, &if_nativepromise,
1290 &if_notnativepromise);
1291
1292 // This adds a fast path for native promises that don't need to
1293 // create NewPromiseCapability.
1294 Bind(&if_nativepromise);
1295 {
1296 Label do_resolve(this);
1297
1298 Node* const result = AllocateAndInitJSPromise(context);
1299 InternalResolvePromise(context, result, value);
1300 Return(result);
1301 }
1302
1303 Bind(&if_notnativepromise);
1304 {
1305 // 4. Let promiseCapability be ? NewPromiseCapability(C).
1306 Node* const capability = NewPromiseCapability(context, receiver);
1307
1308 // 5. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
1309 Callable call_callable = CodeFactory::Call(isolate);
1310 Node* const resolve =
1311 LoadObjectField(capability, JSPromiseCapability::kResolveOffset);
1312 CallJS(call_callable, context, resolve, UndefinedConstant(), value);
1313
1314 // 6. Return promiseCapability.[[Promise]].
1315 Node* const result =
1316 LoadObjectField(capability, JSPromiseCapability::kPromiseOffset);
1317 Return(result);
1318 }
1319 }
1320 }
1321
1210 TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) { 1322 TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
1211 Node* const resolve = Parameter(1); 1323 Node* const resolve = Parameter(1);
1212 Node* const reject = Parameter(2); 1324 Node* const reject = Parameter(2);
1213 Node* const context = Parameter(5); 1325 Node* const context = Parameter(5);
1214 1326
1215 Node* const capability = LoadContextElement( 1327 Node* const capability = LoadContextElement(
1216 context, GetPromiseCapabilityExecutor::kCapabilitySlot); 1328 context, GetPromiseCapabilityExecutor::kCapabilitySlot);
1217 1329
1218 Label if_alreadyinvoked(this, Label::kDeferred); 1330 Label if_alreadyinvoked(this, Label::kDeferred);
1219 GotoIf(WordNotEqual( 1331 GotoIf(WordNotEqual(
(...skipping 20 matching lines...) Expand all
1240 Node* debug_event = Parameter(2); 1352 Node* debug_event = Parameter(2);
1241 Node* context = Parameter(5); 1353 Node* context = Parameter(5);
1242 1354
1243 CSA_ASSERT_JS_ARGC_EQ(this, 2); 1355 CSA_ASSERT_JS_ARGC_EQ(this, 2);
1244 1356
1245 Return(NewPromiseCapability(context, constructor, debug_event)); 1357 Return(NewPromiseCapability(context, constructor, debug_event));
1246 } 1358 }
1247 1359
1248 } // namespace internal 1360 } // namespace internal
1249 } // namespace v8 1361 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins-promise.h ('k') | src/js/promise.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698