OLD | NEW |
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-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 | 7 |
| 8 #include "src/code-factory.h" |
8 #include "src/promise-utils.h" | 9 #include "src/promise-utils.h" |
9 | 10 |
10 namespace v8 { | 11 namespace v8 { |
11 namespace internal { | 12 namespace internal { |
12 | 13 |
13 // ES#sec-promise-resolve-functions | 14 // ES#sec-promise-resolve-functions |
14 // Promise Resolve Functions | 15 // Promise Resolve Functions |
15 BUILTIN(PromiseResolveClosure) { | 16 BUILTIN(PromiseResolveClosure) { |
16 HandleScope scope(isolate); | 17 HandleScope scope(isolate); |
17 | 18 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 &resolve, &reject); | 74 &resolve, &reject); |
74 | 75 |
75 Handle<FixedArray> result = isolate->factory()->NewFixedArray(2); | 76 Handle<FixedArray> result = isolate->factory()->NewFixedArray(2); |
76 result->set(0, *resolve); | 77 result->set(0, *resolve); |
77 result->set(1, *reject); | 78 result->set(1, *reject); |
78 | 79 |
79 return *isolate->factory()->NewJSArrayWithElements(result, FAST_ELEMENTS, 2, | 80 return *isolate->factory()->NewJSArrayWithElements(result, FAST_ELEMENTS, 2, |
80 NOT_TENURED); | 81 NOT_TENURED); |
81 } | 82 } |
82 | 83 |
| 84 void Builtins::Generate_PromiseConstructor( |
| 85 compiler::CodeAssemblerState* state) { |
| 86 CodeStubAssembler a(state); |
| 87 typedef CodeStubAssembler::Variable Variable; |
| 88 typedef CodeStubAssembler::Label Label; |
| 89 typedef compiler::Node Node; |
| 90 |
| 91 Node* const executor = a.Parameter(1); |
| 92 Node* const new_target = a.Parameter(2); |
| 93 Node* const context = a.Parameter(4); |
| 94 Isolate* isolate = a.isolate(); |
| 95 |
| 96 Label if_targetisundefined(&a, Label::kDeferred); |
| 97 |
| 98 a.GotoIf(a.WordEqual(new_target, a.UndefinedConstant()), |
| 99 &if_targetisundefined); |
| 100 |
| 101 Label if_notcallable(&a, Label::kDeferred); |
| 102 |
| 103 a.GotoIf(a.TaggedIsSmi(executor), &if_notcallable); |
| 104 |
| 105 Node* const executor_map = a.LoadMap(executor); |
| 106 a.GotoUnless(a.IsCallableMap(executor_map), &if_notcallable); |
| 107 |
| 108 Node* const native_context = a.LoadNativeContext(context); |
| 109 Node* const promise_fun = |
| 110 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
| 111 |
| 112 Label if_targetisnotmodified(&a), if_targetismodified(&a, Label::kDeferred), |
| 113 run_executor(&a), debug_push(&a, Label::kDeferred); |
| 114 a.Branch(a.WordEqual(promise_fun, new_target), &if_targetisnotmodified, |
| 115 &if_targetismodified); |
| 116 |
| 117 Variable var_result(&a, MachineRepresentation::kTagged), |
| 118 var_reject_call(&a, MachineRepresentation::kTagged), |
| 119 var_reason(&a, MachineRepresentation::kTagged); |
| 120 |
| 121 a.Bind(&if_targetisnotmodified); |
| 122 { |
| 123 Node* const initial_map = a.LoadObjectField( |
| 124 promise_fun, JSFunction::kPrototypeOrInitialMapOffset); |
| 125 |
| 126 Node* const instance = a.AllocateJSObjectFromMap(initial_map); |
| 127 var_result.Bind(instance); |
| 128 a.Branch(a.IsDebugActive(), &debug_push, &run_executor); |
| 129 } |
| 130 |
| 131 a.Bind(&if_targetismodified); |
| 132 { |
| 133 Callable fast_new_object_stub = CodeFactory::FastNewObject(isolate); |
| 134 Node* const instance = |
| 135 a.CallStub(fast_new_object_stub, context, promise_fun, new_target); |
| 136 |
| 137 var_result.Bind(instance); |
| 138 a.Branch(a.IsDebugActive(), &debug_push, &run_executor); |
| 139 } |
| 140 |
| 141 a.Bind(&debug_push); |
| 142 { |
| 143 a.CallRuntime(Runtime::kDebugPushPromise, context, var_result.value()); |
| 144 a.Goto(&run_executor); |
| 145 } |
| 146 |
| 147 a.Bind(&run_executor); |
| 148 { |
| 149 Label out(&a), if_rejectpromise(&a), debug_pop(&a, Label::kDeferred); |
| 150 |
| 151 Node* const key = |
| 152 a.HeapConstant(a.isolate()->factory()->promise_state_symbol()); |
| 153 Node* const value = a.SmiConstant(kPromisePending); |
| 154 Node* const language_mode = a.SmiConstant(STRICT); |
| 155 a.CallRuntime(Runtime::kSetProperty, context, var_result.value(), key, |
| 156 value, language_mode); |
| 157 Node* const resolving_functions = a.CallRuntime( |
| 158 Runtime::kCreateResolvingFunctions, context, var_result.value()); |
| 159 Node* const resolve = |
| 160 a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(0)); |
| 161 Node* const reject = |
| 162 a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(1)); |
| 163 Callable call_callable = CodeFactory::Call(isolate); |
| 164 |
| 165 Node* const maybe_exception = |
| 166 a.CallJS(call_callable, context, executor, a.UndefinedConstant(), |
| 167 resolve, reject); |
| 168 |
| 169 a.GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); |
| 170 a.Branch(a.IsDebugActive(), &debug_pop, &out); |
| 171 |
| 172 a.Bind(&if_rejectpromise); |
| 173 { |
| 174 Callable call_callable = CodeFactory::Call(isolate); |
| 175 a.CallJS(call_callable, context, reject, a.UndefinedConstant(), |
| 176 var_reason.value()); |
| 177 a.Branch(a.IsDebugActive(), &debug_pop, &out); |
| 178 } |
| 179 |
| 180 a.Bind(&debug_pop); |
| 181 a.CallRuntime(Runtime::kDebugPopPromise, context); |
| 182 |
| 183 a.Bind(&out); |
| 184 a.Return(var_result.value()); |
| 185 } |
| 186 |
| 187 // 1. If NewTarget is undefined, throw a TypeError exception. |
| 188 a.Bind(&if_targetisundefined); |
| 189 { |
| 190 Node* const message_id = a.SmiConstant(MessageTemplate::kNotAPromise); |
| 191 a.CallRuntime(Runtime::kThrowTypeError, context, message_id, new_target); |
| 192 a.Return(a.UndefinedConstant()); // Never reached. |
| 193 } |
| 194 |
| 195 // 2. If IsCallable(executor) is false, throw a TypeError exception. |
| 196 a.Bind(&if_notcallable); |
| 197 { |
| 198 Node* const message_id = |
| 199 a.SmiConstant(MessageTemplate::kResolverNotAFunction); |
| 200 a.CallRuntime(Runtime::kThrowTypeError, context, message_id, executor); |
| 201 a.Return(a.UndefinedConstant()); // Never reached. |
| 202 } |
| 203 } |
| 204 |
| 205 void Builtins::Generate_PromiseInternalConstructor( |
| 206 compiler::CodeAssemblerState* state) { |
| 207 typedef compiler::Node Node; |
| 208 CodeStubAssembler a(state); |
| 209 |
| 210 Node* const context = a.Parameter(3); |
| 211 Node* const native_context = a.LoadNativeContext(context); |
| 212 Node* const promise_fun = |
| 213 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
| 214 Node* const initial_map = |
| 215 a.LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); |
| 216 Node* const instance = a.AllocateJSObjectFromMap(initial_map); |
| 217 a.Return(instance); |
| 218 } |
| 219 |
| 220 // TODO(gsathya): Refactor promise.js::IsPromise to use this. |
| 221 void Builtins::Generate_IsPromise(compiler::CodeAssemblerState* state) { |
| 222 CodeStubAssembler a(state); |
| 223 typedef compiler::Node Node; |
| 224 typedef CodeStubAssembler::Label Label; |
| 225 |
| 226 Node* const maybe_promise = a.Parameter(1); |
| 227 Label if_ispromise(&a), if_isnotpromise(&a, Label::kDeferred); |
| 228 a.GotoIf(a.TaggedIsSmi(maybe_promise), &if_isnotpromise); |
| 229 |
| 230 Node* const maybe_promise_type = |
| 231 a.LoadMapInstanceType(a.LoadMap(maybe_promise)); |
| 232 |
| 233 a.Branch(a.Word32Equal(maybe_promise_type, a.Int32Constant(JS_PROMISE_TYPE)), |
| 234 &if_ispromise, &if_isnotpromise); |
| 235 |
| 236 a.Bind(&if_ispromise); |
| 237 a.Return(a.BooleanConstant(true)); |
| 238 |
| 239 a.Bind(&if_isnotpromise); |
| 240 a.Return(a.BooleanConstant(false)); |
| 241 } |
| 242 |
83 } // namespace internal | 243 } // namespace internal |
84 } // namespace v8 | 244 } // namespace v8 |
OLD | NEW |