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

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

Issue 2592933004: [promises] Move Promise.resolve to TF (Closed)
Patch Set: fix test 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
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 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 Node* promise_capability, Node* native_context) { 183 Node* promise_capability, Node* native_context) {
184 int kContextLength = GetPromiseCapabilityExecutor::kContextLength; 184 int kContextLength = GetPromiseCapabilityExecutor::kContextLength;
185 Node* context = CreatePromiseContext(native_context, kContextLength); 185 Node* context = CreatePromiseContext(native_context, kContextLength);
186 StoreContextElementNoWriteBarrier( 186 StoreContextElementNoWriteBarrier(
187 context, GetPromiseCapabilityExecutor::kCapabilitySlot, 187 context, GetPromiseCapabilityExecutor::kCapabilitySlot,
188 promise_capability); 188 promise_capability);
189 return context; 189 return context;
190 } 190 }
191 191
192 Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver( 192 Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver(
193 Node* context, Node* value, MessageTemplate::Template msg_template) { 193 Node* context, Node* value, MessageTemplate::Template msg_template,
194 const char* method_name) {
194 Label out(this), throw_exception(this, Label::kDeferred); 195 Label out(this), throw_exception(this, Label::kDeferred);
195 Variable var_value_map(this, MachineRepresentation::kTagged); 196 Variable var_value_map(this, MachineRepresentation::kTagged);
196 197
197 GotoIf(TaggedIsSmi(value), &throw_exception); 198 GotoIf(TaggedIsSmi(value), &throw_exception);
198 199
199 // Load the instance type of the {value}. 200 // Load the instance type of the {value}.
200 var_value_map.Bind(LoadMap(value)); 201 var_value_map.Bind(LoadMap(value));
201 Node* const value_instance_type = LoadMapInstanceType(var_value_map.value()); 202 Node* const value_instance_type = LoadMapInstanceType(var_value_map.value());
202 203
203 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception); 204 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception);
204 205
205 // The {value} is not a compatible receiver for this method. 206 // The {value} is not a compatible receiver for this method.
206 Bind(&throw_exception); 207 Bind(&throw_exception);
207 { 208 {
209 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.
210 Node* method;
adamk 2017/01/04 19:19:21 Node* const for consistency.
gsathya 2017/01/04 19:37:17 Done.
211 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.
212 ? UndefinedConstant()
213 : HeapConstant(isolate->factory()->NewStringFromAsciiChecked(
214 method_name));
215
208 Node* const message_id = SmiConstant(msg_template); 216 Node* const message_id = SmiConstant(msg_template);
209 CallRuntime(Runtime::kThrowTypeError, context, message_id); 217 CallRuntime(Runtime::kThrowTypeError, context, message_id, method);
210 var_value_map.Bind(UndefinedConstant()); 218 var_value_map.Bind(UndefinedConstant());
211 Goto(&out); // Never reached. 219 Goto(&out); // Never reached.
212 } 220 }
213 221
214 Bind(&out); 222 Bind(&out);
215 return var_value_map.value(); 223 return var_value_map.value();
216 } 224 }
217 225
218 Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) { 226 Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) {
219 Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset); 227 Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 } 566 }
559 567
560 // Promise fast path implementations rely on unmodified JSPromise instances. 568 // Promise fast path implementations rely on unmodified JSPromise instances.
561 // We use a fairly coarse granularity for this and simply check whether both 569 // We use a fairly coarse granularity for this and simply check whether both
562 // the promise itself is unmodified (i.e. its map has not changed) and its 570 // the promise itself is unmodified (i.e. its map has not changed) and its
563 // prototype is unmodified. 571 // prototype is unmodified.
564 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp 572 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp
565 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, 573 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise,
566 Label* if_isunmodified, 574 Label* if_isunmodified,
567 Label* if_ismodified) { 575 Label* if_ismodified) {
568 // TODO(gsathya): Assert if promise is receiver
569 Node* const map = LoadMap(promise);
570 Node* const native_context = LoadNativeContext(context); 576 Node* const native_context = LoadNativeContext(context);
571 Node* const promise_fun = 577 Node* const promise_fun =
572 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); 578 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
579 BranchIfFastPath(native_context, promise_fun, promise, if_isunmodified,
580 if_ismodified);
581 }
582
583 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* native_context,
584 Node* promise_fun,
585 Node* promise,
586 Label* if_isunmodified,
587 Label* if_ismodified) {
588 CSA_ASSERT(this, IsNativeContext(native_context));
589 CSA_ASSERT(this,
590 WordEqual(promise_fun,
591 LoadContextElement(native_context,
592 Context::PROMISE_FUNCTION_INDEX)));
593
594 Node* const map = LoadMap(promise);
573 Node* const initial_map = 595 Node* const initial_map =
574 LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); 596 LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
575 Node* const has_initialmap = WordEqual(map, initial_map); 597 Node* const has_initialmap = WordEqual(map, initial_map);
576 598
577 GotoUnless(has_initialmap, if_ismodified); 599 GotoUnless(has_initialmap, if_ismodified);
578 600
579 Node* const initial_proto_initial_map = 601 Node* const initial_proto_initial_map =
580 LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX); 602 LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX);
581 Node* const proto_map = LoadMap(LoadMapPrototype(map)); 603 Node* const proto_map = LoadMap(LoadMapPrototype(map));
582 Node* const proto_has_initialmap = 604 Node* const proto_has_initialmap =
(...skipping 20 matching lines...) Expand all
603 625
604 Bind(&cycle_check); 626 Bind(&cycle_check);
605 // 6. If SameValue(resolution, promise) is true, then 627 // 6. If SameValue(resolution, promise) is true, then
606 GotoIf(SameValue(promise, result, context), &if_cycle); 628 GotoIf(SameValue(promise, result, context), &if_cycle);
607 629
608 // 7. If Type(resolution) is not Object, then 630 // 7. If Type(resolution) is not Object, then
609 GotoIf(TaggedIsSmi(result), &fulfill); 631 GotoIf(TaggedIsSmi(result), &fulfill);
610 GotoUnless(IsJSReceiver(result), &fulfill); 632 GotoUnless(IsJSReceiver(result), &fulfill);
611 633
612 Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred); 634 Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred);
613 BranchIfFastPath(context, result, &if_nativepromise, &if_notnativepromise); 635 Node* const native_context = LoadNativeContext(context);
636 Node* const promise_fun =
637 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
638 BranchIfFastPath(native_context, promise_fun, result, &if_nativepromise,
639 &if_notnativepromise);
614 640
615 // Resolution is a native promise and if it's already resolved or 641 // Resolution is a native promise and if it's already resolved or
616 // rejected, shortcircuit the resolution procedure by directly 642 // rejected, shortcircuit the resolution procedure by directly
617 // reusing the value from the promise. 643 // reusing the value from the promise.
618 Bind(&if_nativepromise); 644 Bind(&if_nativepromise);
619 { 645 {
620 Node* const thenable_status = 646 Node* const thenable_status =
621 LoadObjectField(result, JSPromise::kStatusOffset); 647 LoadObjectField(result, JSPromise::kStatusOffset);
622 Node* const thenable_value = 648 Node* const thenable_value =
623 LoadObjectField(result, JSPromise::kResultOffset); 649 LoadObjectField(result, JSPromise::kResultOffset);
624 650
625 Label if_isnotpending(this); 651 Label if_isnotpending(this);
626 GotoUnless(SmiEqual(SmiConstant(v8::Promise::kPending), thenable_status), 652 GotoUnless(SmiEqual(SmiConstant(v8::Promise::kPending), thenable_status),
627 &if_isnotpending); 653 &if_isnotpending);
628 654
629 // TODO(gsathya): Use a marker here instead of the actual then 655 // TODO(gsathya): Use a marker here instead of the actual then
630 // callback, and check for the marker in PromiseResolveThenableJob 656 // callback, and check for the marker in PromiseResolveThenableJob
631 // and perform PromiseThen. 657 // and perform PromiseThen.
632 Node* const native_context = LoadNativeContext(context);
633 Node* const then = 658 Node* const then =
634 LoadContextElement(native_context, Context::PROMISE_THEN_INDEX); 659 LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
635 var_then.Bind(then); 660 var_then.Bind(then);
636 Goto(&do_enqueue); 661 Goto(&do_enqueue);
637 662
638 Bind(&if_isnotpending); 663 Bind(&if_isnotpending);
639 { 664 {
640 Label if_fulfilled(this), if_rejected(this); 665 Label if_fulfilled(this), if_rejected(this);
641 Branch(SmiEqual(SmiConstant(v8::Promise::kFulfilled), thenable_status), 666 Branch(SmiEqual(SmiConstant(v8::Promise::kFulfilled), thenable_status),
642 &if_fulfilled, &if_rejected); 667 &if_fulfilled, &if_rejected);
(...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after
1128 Callable getproperty_callable = CodeFactory::GetProperty(isolate); 1153 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
1129 Node* const then = 1154 Node* const then =
1130 CallStub(getproperty_callable, context, promise, then_str); 1155 CallStub(getproperty_callable, context, promise, then_str);
1131 Callable call_callable = CodeFactory::Call(isolate); 1156 Callable call_callable = CodeFactory::Call(isolate);
1132 Node* const result = 1157 Node* const result =
1133 CallJS(call_callable, context, then, promise, on_resolve, on_reject); 1158 CallJS(call_callable, context, then, promise, on_resolve, on_reject);
1134 Return(result); 1159 Return(result);
1135 } 1160 }
1136 } 1161 }
1137 1162
1163 TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
1164 // 1. Let C be the this value.
1165 Node* receiver = Parameter(0);
1166 Node* value = Parameter(1);
1167 Node* context = Parameter(4);
1168 Isolate* isolate = this->isolate();
1169
1170 // 2. If Type(C) is not Object, throw a TypeError exception.
1171 ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1172 "PromiseResolve");
1173
1174 Label if_valueisnativepromise(this), if_valueisnotnativepromise(this),
1175 if_valueisnotpromise(this);
1176
1177 // 3.If IsPromise(x) is true, then
1178 GotoIf(TaggedIsSmi(value), &if_valueisnotpromise);
1179
1180 // This shortcircuits the constructor lookups.
1181 GotoUnless(HasInstanceType(value, JS_PROMISE_TYPE), &if_valueisnotpromise);
1182
1183 // This adds a fast path as non-subclassed native promises don't have
1184 // an observable constructor lookup.
1185 Node* const native_context = LoadNativeContext(context);
1186 Node* const promise_fun =
1187 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1188 BranchIfFastPath(native_context, promise_fun, value, &if_valueisnativepromise,
1189 &if_valueisnotnativepromise);
1190
1191 Bind(&if_valueisnativepromise);
1192 {
1193 GotoUnless(WordEqual(promise_fun, receiver), &if_valueisnotnativepromise);
1194 Return(value);
1195 }
1196
1197 // At this point, value or/and receiver are not native promises, but
1198 // they could be of the same subclass.
1199 Bind(&if_valueisnotnativepromise);
1200 {
1201 // 3.a Let xConstructor be ? Get(x, "constructor").
1202 // The constructor lookup is observable.
1203 Node* const constructor_str =
1204 HeapConstant(isolate->factory()->constructor_string());
1205 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
1206 Node* const constructor =
1207 CallStub(getproperty_callable, context, value, constructor_str);
1208
1209 // 3.b If SameValue(xConstructor, C) is true, return x.
1210 GotoUnless(SameValue(constructor, receiver, context),
1211 &if_valueisnotpromise);
1212
1213 Return(value);
1214 }
1215
1216 Bind(&if_valueisnotpromise);
1217 {
1218 Label if_nativepromise(this), if_notnativepromise(this);
1219 BranchIfFastPath(context, receiver, &if_nativepromise,
1220 &if_notnativepromise);
1221
1222 // This adds a fast path for native promises that don't need to
1223 // create NewPromiseCapability.
1224 Bind(&if_nativepromise);
1225 {
1226 Label do_resolve(this);
1227
1228 Node* const result = AllocateJSPromise(context);
1229 PromiseInit(result);
1230
1231 GotoUnless(IsPromiseHookEnabled(), &do_resolve);
1232 CallRuntime(Runtime::kPromiseHookInit, context, result,
1233 UndefinedConstant());
1234 Goto(&do_resolve);
1235
1236 Bind(&do_resolve);
1237 InternalResolvePromise(context, result, value);
1238 Return(result);
1239 }
1240
1241 Bind(&if_notnativepromise);
1242 {
1243 // 4. Let promiseCapability be ? NewPromiseCapability(C).
1244 Node* const capability = NewPromiseCapability(context, receiver);
1245
1246 // 5. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
1247 Callable call_callable = CodeFactory::Call(isolate);
1248 Node* const resolve =
1249 LoadObjectField(capability, JSPromiseCapability::kResolveOffset);
1250 CallJS(call_callable, context, resolve, UndefinedConstant(), value);
1251
1252 // 6. Return promiseCapability.[[Promise]].
1253 Node* const result =
1254 LoadObjectField(capability, JSPromiseCapability::kPromiseOffset);
1255 Return(result);
1256 }
1257 }
1258 }
1259
1138 TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) { 1260 TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
1139 Node* const resolve = Parameter(1); 1261 Node* const resolve = Parameter(1);
1140 Node* const reject = Parameter(2); 1262 Node* const reject = Parameter(2);
1141 Node* const context = Parameter(5); 1263 Node* const context = Parameter(5);
1142 1264
1143 Node* const capability = LoadContextElement( 1265 Node* const capability = LoadContextElement(
1144 context, GetPromiseCapabilityExecutor::kCapabilitySlot); 1266 context, GetPromiseCapabilityExecutor::kCapabilitySlot);
1145 1267
1146 Label if_alreadyinvoked(this, Label::kDeferred); 1268 Label if_alreadyinvoked(this, Label::kDeferred);
1147 GotoIf(WordNotEqual( 1269 GotoIf(WordNotEqual(
(...skipping 20 matching lines...) Expand all
1168 Node* debug_event = Parameter(2); 1290 Node* debug_event = Parameter(2);
1169 Node* context = Parameter(5); 1291 Node* context = Parameter(5);
1170 1292
1171 CSA_ASSERT_JS_ARGC_EQ(this, 2); 1293 CSA_ASSERT_JS_ARGC_EQ(this, 2);
1172 1294
1173 Return(NewPromiseCapability(context, constructor, debug_event)); 1295 Return(NewPromiseCapability(context, constructor, debug_event));
1174 } 1296 }
1175 1297
1176 } // namespace internal 1298 } // namespace internal
1177 } // namespace v8 1299 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698