Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "src/builtins/builtins-async.h" | |
| 6 #include "src/builtins/builtins-utils.h" | |
| 7 #include "src/builtins/builtins.h" | |
| 8 #include "src/code-factory.h" | |
| 9 #include "src/code-stub-assembler.h" | |
| 10 #include "src/frames-inl.h" | |
| 11 | |
| 12 namespace v8 { | |
| 13 namespace internal { | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 // Describe fields of Context associated with AsyncGeneratorAwait resume | |
| 18 // closures. | |
| 19 class AwaitContext { | |
| 20 public: | |
| 21 enum Fields { kGeneratorSlot = Context::MIN_CONTEXT_SLOTS, kLength }; | |
| 22 }; | |
| 23 | |
| 24 } // anonymous namespace | |
| 25 | |
| 26 // https://tc39.github.io/proposal-async-iteration/ | |
| 27 // Section #sec-asyncgenerator-prototype-next | |
| 28 TF_BUILTIN(AsyncGeneratorPrototypeNext, AsyncBuiltinsAssembler) { | |
| 29 Node* const generator = Parameter(0); | |
| 30 Node* const value = Parameter(1); | |
| 31 Node* const context = Parameter(4); | |
| 32 AsyncGeneratorEnqueue(context, generator, value, | |
| 33 JSAsyncGeneratorObject::kNext, | |
| 34 "[AsyncGenerator].prototype.next"); | |
| 35 } | |
| 36 | |
| 37 // https://tc39.github.io/proposal-async-iteration/ | |
| 38 // Section #sec-asyncgenerator-prototype-return | |
| 39 TF_BUILTIN(AsyncGeneratorPrototypeReturn, AsyncBuiltinsAssembler) { | |
| 40 Node* generator = Parameter(0); | |
| 41 Node* value = Parameter(1); | |
| 42 Node* context = Parameter(4); | |
| 43 AsyncGeneratorEnqueue(context, generator, value, | |
| 44 JSAsyncGeneratorObject::kReturn, | |
| 45 "[AsyncGenerator].prototype.return"); | |
| 46 } | |
| 47 | |
| 48 // https://tc39.github.io/proposal-async-iteration/ | |
| 49 // Section #sec-asyncgenerator-prototype-throw | |
| 50 TF_BUILTIN(AsyncGeneratorPrototypeThrow, AsyncBuiltinsAssembler) { | |
| 51 Node* generator = Parameter(0); | |
| 52 Node* value = Parameter(1); | |
| 53 Node* context = Parameter(4); | |
| 54 AsyncGeneratorEnqueue(context, generator, value, | |
| 55 JSAsyncGeneratorObject::kThrow, | |
| 56 "[AsyncGenerator].prototype.throw"); | |
| 57 } | |
| 58 | |
| 59 TF_BUILTIN(AsyncGeneratorYield, AsyncBuiltinsAssembler) { | |
| 60 Node* const generator = Parameter(0); | |
| 61 Node* const value = Parameter(1); | |
| 62 Node* const context = Parameter(4); | |
| 63 | |
| 64 CSA_ASSERT_JS_ARGC_EQ(this, 1); | |
| 65 CSA_SLOW_ASSERT(this, | |
| 66 HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE)); | |
| 67 | |
| 68 Node* request = TakeFirstAsyncGeneratorRequestFromQueue(generator); | |
| 69 | |
| 70 Node* const promise = | |
| 71 LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset); | |
| 72 | |
| 73 // The request Promise must still be pending at this point. | |
| 74 CSA_SLOW_ASSERT(this, | |
| 75 WordEqual(LoadObjectField(promise, JSPromise::kStatusOffset), | |
| 76 SmiConstant(v8::Promise::kPending))); | |
| 77 | |
| 78 // If a yield expression is reached, we must not be awaiting any value. | |
| 79 CSA_SLOW_ASSERT(this, | |
| 80 IsUndefined(LoadObjectField( | |
| 81 request, AsyncGeneratorRequest::kAwaitedPromiseOffset))); | |
| 82 | |
| 83 Node* const iter_result = AllocateJSIteratorResult(context, value, false); | |
|
jgruber
2017/01/13 13:34:39
I just recently landed CreateIterResultObject, per
caitp
2017/01/13 14:36:04
Sgtm
caitp
2017/01/17 19:23:11
Done.
| |
| 84 | |
| 85 InternalResolvePromise(context, promise, iter_result); | |
| 86 | |
| 87 AsyncGeneratorResumeNext(context, generator); | |
| 88 | |
| 89 Return(UndefinedConstant()); | |
| 90 } | |
| 91 | |
| 92 TF_BUILTIN(AsyncGeneratorAwaitResolveClosure, AsyncBuiltinsAssembler) { | |
| 93 Node* value = Parameter(1); | |
| 94 Node* context = Parameter(4); | |
| 95 | |
| 96 AsyncGeneratorAwaitResumeClosure(context, value, | |
| 97 JSAsyncGeneratorObject::kNext); | |
| 98 Return(UndefinedConstant()); | |
| 99 } | |
| 100 | |
| 101 TF_BUILTIN(AsyncGeneratorAwaitRejectClosure, AsyncBuiltinsAssembler) { | |
| 102 Node* value = Parameter(1); | |
| 103 Node* context = Parameter(4); | |
| 104 | |
| 105 AsyncGeneratorAwaitResumeClosure(context, value, | |
| 106 JSAsyncGeneratorObject::kThrow); | |
| 107 Return(UndefinedConstant()); | |
| 108 } | |
| 109 | |
| 110 TF_BUILTIN(AsyncGeneratorAwaitUncaught, AsyncBuiltinsAssembler) { | |
| 111 const bool kIsCatchable = false; | |
| 112 AsyncGeneratorAwait(kIsCatchable); | |
| 113 } | |
| 114 | |
| 115 TF_BUILTIN(AsyncGeneratorAwaitCaught, AsyncBuiltinsAssembler) { | |
| 116 const bool kIsCatchable = true; | |
| 117 AsyncGeneratorAwait(kIsCatchable); | |
| 118 } | |
| 119 | |
| 120 // Shared implementation for the 3 Async Iterator protocol methods of Async | |
| 121 // Generators. | |
| 122 void AsyncBuiltinsAssembler::AsyncGeneratorEnqueue( | |
| 123 Node* context, Node* generator, Node* value, | |
| 124 JSAsyncGeneratorObject::ResumeMode resume_mode, const char* method_name) { | |
| 125 // AsyncGeneratorEnqueue produces a new Promise, and appends it to the list | |
| 126 // of async generator requests to be executed. If the generator is not | |
| 127 // presently executing, then this method will loop through, processing each | |
| 128 // request from front to back. | |
| 129 // This loop is resides in AsyncGeneratorResumeNext. | |
|
jgruber
2017/01/13 13:34:42
Nit: is resides
| |
| 130 Node* promise = AllocateAndInitJSPromise(context); | |
| 131 | |
| 132 Label enqueue(this), if_receiverisincompatible(this, Label::kDeferred); | |
| 133 | |
| 134 GotoIf(TaggedIsSmi(generator), &if_receiverisincompatible); | |
| 135 Branch(HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE), &enqueue, | |
| 136 &if_receiverisincompatible); | |
| 137 | |
| 138 Bind(&enqueue); | |
| 139 { | |
| 140 Label done(this); | |
| 141 Node* const req = | |
| 142 AllocateAsyncGeneratorRequest(resume_mode, value, promise); | |
| 143 | |
| 144 AddAsyncGeneratorRequestToQueue(generator, req); | |
| 145 | |
| 146 // Let state be generator.[[AsyncGeneratorState]] | |
| 147 // If state is not "executing", then | |
| 148 // Perform AsyncGeneratorResumeNext(Generator) | |
| 149 // Check if the {receiver} is running or already closed. | |
| 150 Node* continuation = | |
| 151 LoadObjectField(generator, JSAsyncGeneratorObject::kContinuationOffset); | |
| 152 | |
| 153 GotoIf(SmiEqual(continuation, | |
| 154 SmiConstant(JSAsyncGeneratorObject::kGeneratorExecuting)), | |
| 155 &done); | |
| 156 | |
| 157 AsyncGeneratorResumeNext(context, generator, continuation); | |
| 158 | |
| 159 Goto(&done); | |
| 160 Bind(&done); | |
| 161 Return(promise); | |
| 162 } | |
| 163 | |
| 164 Bind(&if_receiverisincompatible); | |
| 165 { | |
| 166 Node* native_context = LoadNativeContext(context); | |
| 167 Node* make_type_error = | |
| 168 LoadContextElement(native_context, Context::MAKE_TYPE_ERROR_INDEX); | |
| 169 Handle<String> method = | |
| 170 factory()->NewStringFromAsciiChecked(method_name, TENURED); | |
| 171 Node* error = | |
| 172 CallJS(CodeFactory::Call(isolate()), context, make_type_error, | |
| 173 UndefinedConstant(), | |
| 174 SmiConstant(MessageTemplate::kIncompatibleMethodReceiver), | |
| 175 HeapConstant(method), generator); | |
| 176 | |
| 177 CallRuntime(Runtime::kPromiseReject, context, promise, error, | |
| 178 TrueConstant()); | |
| 179 Return(promise); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 void AsyncBuiltinsAssembler::AsyncGeneratorResumeNext(Node* context, | |
| 184 Node* generator, | |
| 185 Node* continuation) { | |
| 186 // Loop through each queued request, from first to last, and resuming the | |
| 187 // generator. Will not resume generator if resumed with an abrupt completion | |
| 188 // such as via the .throw() or .return() methods, or if an Await is | |
| 189 // in progress. | |
| 190 Variable var_request(this, MachineRepresentation::kTagged); | |
| 191 Variable var_continuation(this, MachineRepresentation::kTaggedSigned); | |
| 192 var_continuation.Bind(continuation); | |
| 193 | |
| 194 Variable* loop_vars[] = {&var_request, &var_continuation}; | |
| 195 Label loop(this, arraysize(loop_vars), | |
| 196 reinterpret_cast<Variable **>(loop_vars)), | |
| 197 done(this); | |
| 198 | |
| 199 var_request.Bind( | |
| 200 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset)); | |
| 201 Branch(WordEqual(var_request.value(), UndefinedConstant()), &done, &loop); | |
| 202 Bind(&loop); | |
| 203 { | |
| 204 AsyncGeneratorResumeNextStep(context, generator, var_request.value(), | |
| 205 var_continuation.value(), &done); | |
| 206 | |
| 207 var_continuation.Bind(LoadObjectField( | |
| 208 generator, JSAsyncGeneratorObject::kContinuationOffset)); | |
| 209 var_request.Bind( | |
| 210 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset)); | |
| 211 | |
| 212 // Continue loop if there is another request queued up. | |
| 213 Branch(WordEqual(var_request.value(), UndefinedConstant()), &done, &loop); | |
| 214 } | |
| 215 | |
| 216 Bind(&done); | |
| 217 } | |
| 218 | |
| 219 void AsyncBuiltinsAssembler::AsyncGeneratorResumeNextStep(Node* context, | |
| 220 Node* generator, | |
| 221 Node* request, | |
| 222 Node* continuation, | |
| 223 Label* exit_loop) { | |
| 224 Variable var_return(this, MachineRepresentation::kTagged); | |
| 225 var_return.Bind(UndefinedConstant()); | |
| 226 CSA_SLOW_ASSERT(this, HasInstanceType(request, ASYNC_GENERATOR_REQUEST_TYPE)); | |
| 227 | |
| 228 Label start(this), loop_next(this); | |
| 229 | |
| 230 // Stop consuming the AsyncGeneratorRequest queue and resuming the generator | |
| 231 // if an Await is in progress. | |
| 232 Node* awaited = | |
| 233 LoadObjectField(request, AsyncGeneratorRequest::kAwaitedPromiseOffset); | |
| 234 Branch(IsUndefined(awaited), &start, exit_loop); | |
| 235 | |
| 236 Bind(&start); | |
| 237 | |
| 238 // Let completion be next.[[Completion]] | |
| 239 Node* resume_mode = | |
| 240 LoadObjectField(request, AsyncGeneratorRequest::kResumeModeOffset); | |
| 241 Node* value = LoadObjectField(request, AsyncGeneratorRequest::kValueOffset); | |
| 242 | |
| 243 // If completion is an abrupt completion, then | |
| 244 Label if_abruptcompletion(this), check_ifcompleted(this), | |
| 245 resume_generator(this), if_return(this, &var_return), if_throw(this); | |
| 246 Branch(SmiEqual(resume_mode, SmiConstant(JSAsyncGeneratorObject::kNext)), | |
| 247 &check_ifcompleted, &if_abruptcompletion); | |
| 248 | |
| 249 Bind(&if_abruptcompletion); | |
| 250 { | |
| 251 Label check_completed(this), if_completed(this); | |
| 252 | |
| 253 // If state is "suspendedStart", then | |
| 254 // Set generator.[[AsyncGeneratorState]] to "completed" | |
| 255 // Set state to "completed" | |
| 256 GotoIf(WordNotEqual(continuation, SmiConstant(0)), &check_completed); | |
| 257 StoreObjectField(generator, JSAsyncGeneratorObject::kContinuationOffset, | |
|
jgruber
2017/01/13 13:34:36
I guess we could use the NoWriteBarrier variant he
caitp
2017/01/17 19:23:11
Done.
| |
| 258 SmiConstant(JSAsyncGeneratorObject::kGeneratorClosed)); | |
| 259 Goto(&if_completed); | |
| 260 | |
| 261 Bind(&check_completed); | |
| 262 Branch(WordEqual(continuation, | |
|
jgruber
2017/01/13 13:34:38
SmiEqual here and at other smi comparisons.
caitp
2017/01/17 19:23:11
Done.
| |
| 263 SmiConstant(JSAsyncGeneratorObject::kGeneratorClosed)), | |
| 264 &if_completed, &resume_generator); | |
| 265 | |
| 266 Bind(&if_completed); | |
| 267 { | |
| 268 // If state is "completed", then | |
| 269 // If completion.[[Type]] is return, then return | |
| 270 // ! AsyncGeneratorResolve(generator, completion.[[Value]], true). | |
| 271 // Else, return ! AsyncGeneratorReject(generator, | |
| 272 // completion.[[Value]]) | |
| 273 var_return.Bind(value); | |
| 274 Branch( | |
| 275 WordEqual(resume_mode, SmiConstant(JSAsyncGeneratorObject::kReturn)), | |
| 276 &if_return, &if_throw); | |
| 277 } | |
| 278 } | |
| 279 | |
| 280 Bind(&check_ifcompleted); | |
| 281 { | |
| 282 // Else if state is "completed", then return ! | |
| 283 // AsyncGeneratorResolve(generator, undefined, true). | |
| 284 Branch(WordEqual(continuation, | |
| 285 SmiConstant(JSAsyncGeneratorObject::kGeneratorClosed)), | |
| 286 &if_return, &resume_generator); | |
| 287 } | |
| 288 | |
| 289 Bind(&resume_generator); | |
| 290 { | |
| 291 CSA_ASSERT(this, SmiAboveOrEqual(continuation, SmiConstant(0))); | |
| 292 Node* result = CallStub(CodeFactory::ResumeGenerator(isolate()), context, | |
| 293 value, generator, resume_mode); | |
| 294 Goto(&loop_next); | |
| 295 } | |
| 296 | |
| 297 Bind(&if_return); | |
| 298 { | |
| 299 Node* const request = TakeFirstAsyncGeneratorRequestFromQueue(generator); | |
| 300 Node* const promise = | |
| 301 LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset); | |
| 302 Node* const result = | |
| 303 AllocateJSIteratorResult(context, var_return.value(), true); | |
| 304 PromiseFulfill(context, promise, result, v8::Promise::kFulfilled); | |
| 305 Goto(&loop_next); | |
| 306 } | |
| 307 | |
| 308 Bind(&if_throw); | |
| 309 { | |
| 310 Node* request = TakeFirstAsyncGeneratorRequestFromQueue(generator); | |
| 311 | |
| 312 // Let promiseCapability be next.[[Capability]]. | |
| 313 Node* promise = | |
| 314 LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset); | |
| 315 | |
| 316 // Perform ! Call(promiseCapability.[[Reject]], undefined, « exception »). | |
| 317 CallRuntime(Runtime::kPromiseReject, context, promise, value, | |
| 318 TrueConstant()); | |
| 319 Goto(&loop_next); | |
| 320 } | |
| 321 | |
| 322 Bind(&loop_next); | |
| 323 } | |
| 324 | |
| 325 Node* AsyncBuiltinsAssembler::AllocateAsyncGeneratorRequest( | |
| 326 JSAsyncGeneratorObject::ResumeMode resume_mode, Node* resume_value, | |
| 327 Node* promise) { | |
| 328 CSA_SLOW_ASSERT(this, HasInstanceType(promise, JS_PROMISE_TYPE)); | |
| 329 Node* request = Allocate(AsyncGeneratorRequest::kSize); | |
| 330 StoreMapNoWriteBarrier(request, Heap::kAsyncGeneratorRequestMapRootIndex); | |
| 331 StoreObjectFieldNoWriteBarrier(request, AsyncGeneratorRequest::kNextOffset, | |
| 332 UndefinedConstant()); | |
| 333 StoreObjectFieldNoWriteBarrier(request, | |
| 334 AsyncGeneratorRequest::kResumeModeOffset, | |
| 335 SmiConstant(resume_mode)); | |
| 336 StoreObjectFieldNoWriteBarrier(request, AsyncGeneratorRequest::kValueOffset, | |
| 337 resume_value); | |
| 338 StoreObjectFieldNoWriteBarrier(request, AsyncGeneratorRequest::kPromiseOffset, | |
| 339 promise); | |
| 340 StoreObjectFieldNoWriteBarrier(request, | |
| 341 AsyncGeneratorRequest::kAwaitedPromiseOffset, | |
| 342 UndefinedConstant()); | |
| 343 return request; | |
| 344 } | |
| 345 | |
| 346 void AsyncBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure( | |
| 347 Node* context, Node* value, | |
| 348 JSAsyncGeneratorObject::ResumeMode resume_mode) { | |
| 349 Label done(this); | |
| 350 Node* const generator = | |
| 351 LoadContextElement(context, AwaitContext::kGeneratorSlot); | |
| 352 CSA_SLOW_ASSERT(this, | |
| 353 HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE)); | |
| 354 | |
| 355 Node* const request = | |
| 356 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset); | |
| 357 CSA_SLOW_ASSERT(this, HasInstanceType(request, ASYNC_GENERATOR_REQUEST_TYPE)); | |
| 358 | |
| 359 Node* const promise = | |
| 360 LoadObjectField(request, AsyncGeneratorRequest::kAwaitedPromiseOffset); | |
| 361 CSA_SLOW_ASSERT(this, HasInstanceType(promise, JS_PROMISE_TYPE)); | |
| 362 CSA_SLOW_ASSERT( | |
| 363 this, WordNotEqual(LoadObjectField(promise, JSPromise::kStatusOffset), | |
| 364 SmiConstant(v8::Promise::kPending))); | |
| 365 | |
| 366 StoreObjectField(request, AsyncGeneratorRequest::kAwaitedPromiseOffset, | |
|
jgruber
2017/01/13 13:34:36
NoWriteBarrier
caitp
2017/01/13 14:36:04
Acknowledged.
caitp
2017/01/17 19:23:11
and done
| |
| 367 UndefinedConstant()); | |
| 368 | |
| 369 Node* const continuation = | |
| 370 LoadObjectField(generator, JSAsyncGeneratorObject::kContinuationOffset); | |
| 371 | |
| 372 GotoUnless(SmiAboveOrEqual(continuation, SmiConstant(0)), &done); | |
|
jgruber
2017/01/13 13:34:35
Isn't an unsigned '>= 0' comparison always true?
caitp
2017/01/13 14:36:04
If the generator is executing or closed, no.
jgruber
2017/01/13 15:46:40
My point was that there is no way to make SmiAbove
caitp
2017/01/17 19:23:11
I understand now, per offline discussion. Changed
| |
| 373 | |
| 374 CallStub(CodeFactory::ResumeGenerator(isolate()), context, value, generator, | |
| 375 SmiConstant(resume_mode)); | |
| 376 | |
| 377 Goto(&done); | |
| 378 Bind(&done); | |
| 379 AsyncGeneratorResumeNext(context, generator); | |
| 380 } | |
| 381 | |
| 382 void AsyncBuiltinsAssembler::AsyncGeneratorAwait(bool is_catchable) { | |
| 383 Node* generator = Parameter(1); | |
| 384 Node* value = Parameter(2); | |
| 385 Node* context = Parameter(5); | |
| 386 | |
| 387 CSA_ASSERT_JS_ARGC_EQ(this, 2); | |
| 388 | |
| 389 CSA_SLOW_ASSERT(this, | |
| 390 HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE)); | |
| 391 | |
| 392 Node* const request = | |
| 393 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset); | |
| 394 CSA_SLOW_ASSERT(this, WordNotEqual(request, UndefinedConstant())); | |
| 395 | |
| 396 NodeGenerator1 closure_context = [&](Node* native_context) -> Node* { | |
| 397 Node* const context = | |
| 398 CreatePromiseContext(native_context, AwaitContext::kLength); | |
| 399 StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot, | |
| 400 generator); | |
| 401 return context; | |
| 402 }; | |
| 403 | |
| 404 Node* outer_promise = | |
| 405 LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset); | |
| 406 | |
| 407 const int reject_index = Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN; | |
| 408 STATIC_ASSERT((Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN + 1) == | |
| 409 Context::ASYNC_GENERATOR_AWAIT_RESOLVE_SHARED_FUN); | |
| 410 | |
| 411 Node* promise = Await(context, generator, value, outer_promise, | |
| 412 closure_context, reject_index, is_catchable); | |
| 413 | |
| 414 CSA_SLOW_ASSERT(this, | |
| 415 IsUndefined(LoadObjectField( | |
| 416 request, AsyncGeneratorRequest::kAwaitedPromiseOffset))); | |
| 417 StoreObjectField(request, AsyncGeneratorRequest::kAwaitedPromiseOffset, | |
| 418 promise); | |
| 419 Return(UndefinedConstant()); | |
| 420 } | |
| 421 | |
| 422 void AsyncBuiltinsAssembler::AddAsyncGeneratorRequestToQueue(Node* generator, | |
| 423 Node* request) { | |
| 424 Variable var_current(this, MachineRepresentation::kTagged); | |
| 425 Label empty(this), loop(this, &var_current), done(this); | |
| 426 | |
| 427 var_current.Bind( | |
| 428 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset)); | |
| 429 Branch(IsUndefined(var_current.value()), &empty, &loop); | |
| 430 | |
| 431 Bind(&empty); | |
| 432 { | |
| 433 StoreObjectField(generator, JSAsyncGeneratorObject::kQueueOffset, request); | |
| 434 Goto(&done); | |
| 435 } | |
| 436 | |
| 437 Bind(&loop); | |
| 438 { | |
| 439 Label loop_next(this), next_empty(this); | |
| 440 Node* current = var_current.value(); | |
| 441 Node* next = LoadObjectField(current, AsyncGeneratorRequest::kNextOffset); | |
| 442 | |
| 443 Branch(IsUndefined(next), &next_empty, &loop_next); | |
| 444 Bind(&next_empty); | |
| 445 { | |
| 446 StoreObjectField(current, AsyncGeneratorRequest::kNextOffset, request); | |
| 447 Goto(&done); | |
| 448 } | |
| 449 | |
| 450 Bind(&loop_next); | |
| 451 { | |
| 452 var_current.Bind(next); | |
| 453 Goto(&loop); | |
| 454 } | |
| 455 } | |
| 456 Bind(&done); | |
| 457 } | |
| 458 | |
| 459 Node* AsyncBuiltinsAssembler::TakeFirstAsyncGeneratorRequestFromQueue( | |
| 460 Node* generator) { | |
| 461 // Removes and returns the first AsyncGeneratorRequest from a | |
| 462 // JSAsyncGeneratorObject's queue. Asserts that the queue is not empty. | |
| 463 CSA_SLOW_ASSERT(this, | |
| 464 HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE)); | |
| 465 | |
| 466 Node* request = | |
| 467 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset); | |
| 468 CSA_SLOW_ASSERT(this, WordNotEqual(request, UndefinedConstant())); | |
| 469 | |
| 470 Node* next = LoadObjectField(request, AsyncGeneratorRequest::kNextOffset); | |
| 471 | |
| 472 StoreObjectField(generator, JSAsyncGeneratorObject::kQueueOffset, next); | |
| 473 return request; | |
| 474 } | |
| 475 | |
| 476 } // namespace internal | |
| 477 } // namespace v8 | |
| OLD | NEW |