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); | |
| 84 | |
| 85 InternalResolvePromise(context, promise, iter_result); | |
| 86 | |
| 87 AsyncGeneratorResumeNext(context, generator); | |
| 88 | |
| 89 Return(UndefinedConstant()); | |
| 90 } | |
| 91 | |
| 92 TF_BUILTIN(AsyncGeneratorRawYield, AsyncBuiltinsAssembler) { | |
| 93 Node* const generator = Parameter(0); | |
| 94 Node* const value = Parameter(1); | |
| 95 Node* const context = Parameter(4); | |
| 96 | |
| 97 CSA_ASSERT_JS_ARGC_EQ(this, 1); | |
| 98 CSA_SLOW_ASSERT(this, | |
| 99 HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE)); | |
| 100 | |
| 101 Node* request = TakeFirstAsyncGeneratorRequestFromQueue(generator); | |
| 102 | |
| 103 Node* const promise = | |
| 104 LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset); | |
| 105 | |
| 106 // The request Promise must still be pending at this point. | |
| 107 CSA_SLOW_ASSERT(this, | |
| 108 WordEqual(LoadObjectField(promise, JSPromise::kStatusOffset), | |
| 109 SmiConstant(v8::Promise::kPending))); | |
| 110 | |
| 111 // If a yield expression is reached, we must not be awaiting any value. | |
| 112 CSA_SLOW_ASSERT(this, | |
| 113 IsUndefined(LoadObjectField( | |
| 114 request, AsyncGeneratorRequest::kAwaitedPromiseOffset))); | |
| 115 | |
| 116 InternalResolvePromise(context, promise, value); | |
| 117 | |
| 118 AsyncGeneratorResumeNext(context, generator); | |
| 119 | |
| 120 Return(UndefinedConstant()); | |
| 121 } | |
| 122 | |
| 123 TF_BUILTIN(AsyncGeneratorAwaitResolveClosure, AsyncBuiltinsAssembler) { | |
| 124 Node* value = Parameter(1); | |
| 125 Node* context = Parameter(4); | |
| 126 | |
| 127 AsyncGeneratorAwaitResumeClosure(context, value, | |
| 128 JSAsyncGeneratorObject::kNext); | |
| 129 Return(UndefinedConstant()); | |
| 130 } | |
| 131 | |
| 132 TF_BUILTIN(AsyncGeneratorAwaitRejectClosure, AsyncBuiltinsAssembler) { | |
| 133 Node* value = Parameter(1); | |
| 134 Node* context = Parameter(4); | |
| 135 | |
| 136 AsyncGeneratorAwaitResumeClosure(context, value, | |
| 137 JSAsyncGeneratorObject::kThrow); | |
| 138 Return(UndefinedConstant()); | |
| 139 } | |
| 140 | |
| 141 TF_BUILTIN(AsyncGeneratorAwaitUncaught, AsyncBuiltinsAssembler) { | |
| 142 const bool kIsCatchable = false; | |
| 143 AsyncGeneratorAwait(kIsCatchable); | |
| 144 } | |
| 145 | |
| 146 TF_BUILTIN(AsyncGeneratorAwaitCaught, AsyncBuiltinsAssembler) { | |
| 147 const bool kIsCatchable = true; | |
| 148 AsyncGeneratorAwait(kIsCatchable); | |
| 149 } | |
| 150 | |
| 151 // Shared implementation for the 3 Async Iterator protocol methods of Async | |
| 152 // Generators. | |
| 153 void AsyncBuiltinsAssembler::AsyncGeneratorEnqueue( | |
| 154 Node* context, Node* generator, Node* value, | |
| 155 JSAsyncGeneratorObject::ResumeMode resume_mode, const char* method_name) { | |
| 156 // AsyncGeneratorEnqueue produces a new Promise, and appends it to the list | |
| 157 // of async generator requests to be executed. If the generator is not | |
| 158 // presently executing, then this method will loop through, processing each | |
| 159 // request from front to back. | |
| 160 // This loop is resides in AsyncGeneratorResumeNext. | |
| 161 Node* promise = AllocateAndInitJSPromise(context); | |
| 162 | |
| 163 Label enqueue(this), if_receiverisincompatible(this, Label::kDeferred); | |
| 164 | |
| 165 GotoIf(TaggedIsSmi(generator), &if_receiverisincompatible); | |
| 166 Branch(HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE), &enqueue, | |
| 167 &if_receiverisincompatible); | |
| 168 | |
| 169 Bind(&enqueue); | |
| 170 { | |
| 171 Label done(this); | |
| 172 Node* const req = | |
| 173 AllocateAsyncGeneratorRequest(resume_mode, value, promise); | |
| 174 | |
| 175 AddAsyncGeneratorRequestToQueue(generator, req); | |
| 176 | |
| 177 // Let state be generator.[[AsyncGeneratorState]] | |
| 178 // If state is not "executing", then | |
| 179 // Perform AsyncGeneratorResumeNext(Generator) | |
| 180 // Check if the {receiver} is running or already closed. | |
| 181 Node* continuation = | |
| 182 LoadObjectField(generator, JSAsyncGeneratorObject::kContinuationOffset); | |
| 183 | |
| 184 GotoIf(SmiEqual(continuation, | |
| 185 SmiConstant(JSAsyncGeneratorObject::kGeneratorExecuting)), | |
| 186 &done); | |
| 187 | |
| 188 AsyncGeneratorResumeNext(context, generator, continuation); | |
| 189 | |
| 190 Goto(&done); | |
| 191 Bind(&done); | |
| 192 Return(promise); | |
| 193 } | |
| 194 | |
| 195 Bind(&if_receiverisincompatible); | |
| 196 { | |
| 197 Node* native_context = LoadNativeContext(context); | |
| 198 Node* make_type_error = | |
| 199 LoadContextElement(native_context, Context::MAKE_TYPE_ERROR_INDEX); | |
| 200 Handle<String> method = | |
| 201 factory()->NewStringFromAsciiChecked(method_name, TENURED); | |
| 202 Node* error = | |
| 203 CallJS(CodeFactory::Call(isolate()), context, make_type_error, | |
| 204 UndefinedConstant(), | |
| 205 SmiConstant(MessageTemplate::kIncompatibleMethodReceiver), | |
| 206 HeapConstant(method), generator); | |
| 207 | |
| 208 CallRuntime(Runtime::kPromiseReject, context, promise, error, | |
| 209 TrueConstant()); | |
| 210 Return(promise); | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 void AsyncBuiltinsAssembler::AsyncGeneratorResumeNext(Node* context, | |
| 215 Node* generator, | |
| 216 Node* continuation) { | |
| 217 // Loop through each queued request, from first to last, and resuming the | |
| 218 // generator. Will not resume generator if resumed with an abrupt completion | |
| 219 // such as via the .throw() or .return() methods, or if an Await is | |
| 220 // in progress. | |
| 221 Variable var_request(this, MachineRepresentation::kTagged); | |
| 222 Variable var_continuation(this, MachineRepresentation::kTaggedSigned); | |
| 223 var_continuation.Bind(continuation); | |
| 224 | |
| 225 Variable* loop_vars[] = {&var_request, &var_continuation}; | |
| 226 Label loop(this, arraysize(loop_vars), | |
| 227 reinterpret_cast<Variable **>(loop_vars)), | |
| 228 done(this); | |
| 229 | |
| 230 var_request.Bind( | |
| 231 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset)); | |
| 232 Branch(WordEqual(var_request.value(), UndefinedConstant()), &done, &loop); | |
| 233 Bind(&loop); | |
| 234 { | |
| 235 AsyncGeneratorResumeNextStep(context, generator, var_request.value(), | |
| 236 var_continuation.value(), &done); | |
| 237 | |
| 238 var_continuation.Bind(LoadObjectField( | |
| 239 generator, JSAsyncGeneratorObject::kContinuationOffset)); | |
| 240 var_request.Bind( | |
| 241 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset)); | |
| 242 | |
| 243 // Continue loop if there is another request queued up. | |
| 244 Branch(WordEqual(var_request.value(), UndefinedConstant()), &done, &loop); | |
| 245 } | |
| 246 | |
| 247 Bind(&done); | |
| 248 } | |
| 249 | |
| 250 void AsyncBuiltinsAssembler::AsyncGeneratorResumeNextStep(Node* context, | |
| 251 Node* generator, | |
| 252 Node* request, | |
| 253 Node* continuation, | |
| 254 Label* exit_loop) { | |
| 255 Variable var_return(this, MachineRepresentation::kTagged); | |
| 256 var_return.Bind(UndefinedConstant()); | |
| 257 CSA_SLOW_ASSERT(this, HasInstanceType(request, ASYNC_GENERATOR_REQUEST_TYPE)); | |
| 258 | |
| 259 Label start(this), loop_next(this); | |
| 260 | |
| 261 // Stop consuming the AsyncGeneratorRequest queue and resuming the generator | |
| 262 // if an Await is in progress. | |
| 263 Node* awaited = | |
| 264 LoadObjectField(request, AsyncGeneratorRequest::kAwaitedPromiseOffset); | |
| 265 Branch(IsUndefined(awaited), &start, exit_loop); | |
| 266 | |
| 267 Bind(&start); | |
| 268 | |
| 269 // Let completion be next.[[Completion]] | |
| 270 Node* resume_mode = | |
| 271 LoadObjectField(request, AsyncGeneratorRequest::kResumeModeOffset); | |
| 272 Node* value = LoadObjectField(request, AsyncGeneratorRequest::kValueOffset); | |
| 273 | |
| 274 // If completion is an abrupt completion, then | |
| 275 Label if_abruptcompletion(this), check_ifcompleted(this), | |
| 276 resume_generator(this), if_return(this, &var_return), if_throw(this); | |
| 277 Branch(SmiEqual(resume_mode, SmiConstant(JSAsyncGeneratorObject::kNext)), | |
| 278 &check_ifcompleted, &if_abruptcompletion); | |
| 279 | |
| 280 Bind(&if_abruptcompletion); | |
| 281 { | |
| 282 Label check_completed(this), if_completed(this); | |
| 283 | |
| 284 // If state is "suspendedStart", then | |
| 285 // Set generator.[[AsyncGeneratorState]] to "completed" | |
| 286 // Set state to "completed" | |
| 287 GotoIf(WordNotEqual(continuation, SmiConstant(0)), &check_completed); | |
| 288 StoreObjectField(generator, JSAsyncGeneratorObject::kContinuationOffset, | |
| 289 SmiConstant(JSAsyncGeneratorObject::kGeneratorClosed)); | |
| 290 Goto(&if_completed); | |
| 291 | |
| 292 Bind(&check_completed); | |
| 293 Branch(WordEqual(continuation, | |
| 294 SmiConstant(JSAsyncGeneratorObject::kGeneratorClosed)), | |
| 295 &if_completed, &resume_generator); | |
| 296 | |
| 297 Bind(&if_completed); | |
| 298 { | |
| 299 // If state is "completed", then | |
| 300 // If completion.[[Type]] is return, then return | |
| 301 // ! AsyncGeneratorResolve(generator, completion.[[Value]], true). | |
| 302 // Else, return ! AsyncGeneratorReject(generator, | |
| 303 // completion.[[Value]]) | |
| 304 var_return.Bind(value); | |
| 305 Branch( | |
| 306 WordEqual(resume_mode, SmiConstant(JSAsyncGeneratorObject::kReturn)), | |
| 307 &if_return, &if_throw); | |
| 308 } | |
| 309 } | |
| 310 | |
| 311 Bind(&check_ifcompleted); | |
| 312 { | |
| 313 // Else if state is "completed", then return ! | |
| 314 // AsyncGeneratorResolve(generator, undefined, true). | |
| 315 Branch(WordEqual(continuation, | |
| 316 SmiConstant(JSAsyncGeneratorObject::kGeneratorClosed)), | |
| 317 &if_return, &resume_generator); | |
| 318 } | |
| 319 | |
| 320 Bind(&resume_generator); | |
| 321 { | |
| 322 CSA_ASSERT(this, SmiAboveOrEqual(continuation, SmiConstant(0))); | |
| 323 Node* result = CallStub(CodeFactory::ResumeGenerator(isolate()), context, | |
| 324 value, generator, resume_mode); | |
| 325 Goto(&loop_next); | |
| 326 } | |
| 327 | |
| 328 Bind(&if_return); | |
| 329 { | |
| 330 Node* const request = TakeFirstAsyncGeneratorRequestFromQueue(generator); | |
| 331 Node* const promise = | |
| 332 LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset); | |
| 333 Node* const result = | |
| 334 AllocateJSIteratorResult(context, var_return.value(), true); | |
| 335 PromiseFulfill(context, promise, result, v8::Promise::kFulfilled); | |
| 336 Goto(&loop_next); | |
| 337 } | |
| 338 | |
| 339 Bind(&if_throw); | |
| 340 { | |
| 341 Node* request = TakeFirstAsyncGeneratorRequestFromQueue(generator); | |
| 342 | |
| 343 // Let promiseCapability be next.[[Capability]]. | |
| 344 Node* promise = | |
| 345 LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset); | |
| 346 | |
| 347 // Perform ! Call(promiseCapability.[[Reject]], undefined, « exception »). | |
| 348 CallRuntime(Runtime::kPromiseReject, context, promise, value, | |
| 349 TrueConstant()); | |
| 350 Goto(&loop_next); | |
| 351 } | |
| 352 | |
| 353 Bind(&loop_next); | |
| 354 } | |
| 355 | |
| 356 Node* AsyncBuiltinsAssembler::AllocateAsyncGeneratorRequest( | |
| 357 JSAsyncGeneratorObject::ResumeMode resume_mode, Node* resume_value, | |
| 358 Node* promise) { | |
| 359 CSA_SLOW_ASSERT(this, HasInstanceType(promise, JS_PROMISE_TYPE)); | |
| 360 Node* request = Allocate(AsyncGeneratorRequest::kSize); | |
| 361 StoreMapNoWriteBarrier(request, Heap::kAsyncGeneratorRequestMapRootIndex); | |
| 362 StoreObjectFieldNoWriteBarrier(request, AsyncGeneratorRequest::kNextOffset, | |
| 363 UndefinedConstant()); | |
| 364 StoreObjectFieldNoWriteBarrier(request, | |
| 365 AsyncGeneratorRequest::kResumeModeOffset, | |
| 366 SmiConstant(resume_mode)); | |
| 367 StoreObjectFieldNoWriteBarrier(request, AsyncGeneratorRequest::kValueOffset, | |
| 368 resume_value); | |
| 369 StoreObjectFieldNoWriteBarrier(request, AsyncGeneratorRequest::kPromiseOffset, | |
| 370 promise); | |
| 371 StoreObjectFieldNoWriteBarrier(request, | |
| 372 AsyncGeneratorRequest::kAwaitedPromiseOffset, | |
| 373 UndefinedConstant()); | |
| 374 return request; | |
| 375 } | |
| 376 | |
| 377 void AsyncBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure( | |
| 378 Node* context, Node* value, | |
| 379 JSAsyncGeneratorObject::ResumeMode resume_mode) { | |
| 380 Label done(this); | |
| 381 Node* const generator = | |
| 382 LoadContextElement(context, AwaitContext::kGeneratorSlot); | |
| 383 CSA_SLOW_ASSERT(this, | |
| 384 HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE)); | |
| 385 | |
| 386 Node* const request = | |
| 387 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset); | |
| 388 CSA_SLOW_ASSERT(this, HasInstanceType(request, ASYNC_GENERATOR_REQUEST_TYPE)); | |
| 389 | |
| 390 Node* const promise = | |
| 391 LoadObjectField(request, AsyncGeneratorRequest::kAwaitedPromiseOffset); | |
| 392 CSA_SLOW_ASSERT(this, HasInstanceType(promise, JS_PROMISE_TYPE)); | |
| 393 CSA_SLOW_ASSERT( | |
| 394 this, WordNotEqual(LoadObjectField(promise, JSPromise::kStatusOffset), | |
| 395 SmiConstant(v8::Promise::kPending))); | |
| 396 | |
| 397 StoreObjectField(request, AsyncGeneratorRequest::kAwaitedPromiseOffset, | |
| 398 UndefinedConstant()); | |
| 399 | |
| 400 Node* const continuation = | |
| 401 LoadObjectField(generator, JSAsyncGeneratorObject::kContinuationOffset); | |
| 402 | |
| 403 GotoUnless(SmiAboveOrEqual(continuation, SmiConstant(0)), &done); | |
| 404 CallStub(CodeFactory::ResumeAwaitedGenerator(isolate()), context, value, | |
| 405 generator, SmiConstant(resume_mode)); | |
| 406 | |
| 407 Goto(&done); | |
| 408 Bind(&done); | |
| 409 AsyncGeneratorResumeNext(context, generator); | |
| 410 } | |
| 411 | |
| 412 void AsyncBuiltinsAssembler::AsyncGeneratorAwait(bool is_catchable) { | |
| 413 Node* generator = Parameter(1); | |
| 414 Node* value = Parameter(2); | |
| 415 Node* context = Parameter(5); | |
| 416 | |
| 417 CSA_ASSERT_JS_ARGC_EQ(this, 2); | |
| 418 | |
| 419 CSA_SLOW_ASSERT(this, | |
| 420 HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE)); | |
| 421 | |
| 422 Node* const request = | |
| 423 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset); | |
| 424 CSA_SLOW_ASSERT(this, WordNotEqual(request, UndefinedConstant())); | |
| 425 | |
| 426 NodeGenerator1 closure_context = [&](Node* native_context) -> Node* { | |
| 427 Node* const context = | |
| 428 CreatePromiseContext(native_context, AwaitContext::kLength); | |
| 429 StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot, | |
| 430 generator); | |
| 431 return context; | |
| 432 }; | |
|
Dan Ehrenberg
2017/01/13 22:09:02
I'm a little surprised by this sort of usage of co
| |
| 433 | |
| 434 Node* outer_promise = | |
| 435 LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset); | |
| 436 | |
| 437 const int reject_index = Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN; | |
| 438 STATIC_ASSERT((Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN + 1) == | |
| 439 Context::ASYNC_GENERATOR_AWAIT_RESOLVE_SHARED_FUN); | |
| 440 | |
| 441 Node* promise = Await(context, generator, value, outer_promise, | |
| 442 closure_context, reject_index, is_catchable); | |
| 443 | |
| 444 CSA_SLOW_ASSERT(this, | |
| 445 IsUndefined(LoadObjectField( | |
| 446 request, AsyncGeneratorRequest::kAwaitedPromiseOffset))); | |
| 447 StoreObjectField(request, AsyncGeneratorRequest::kAwaitedPromiseOffset, | |
| 448 promise); | |
| 449 Return(UndefinedConstant()); | |
| 450 } | |
| 451 | |
| 452 void AsyncBuiltinsAssembler::AddAsyncGeneratorRequestToQueue(Node* generator, | |
| 453 Node* request) { | |
| 454 Variable var_current(this, MachineRepresentation::kTagged); | |
| 455 Label empty(this), loop(this, &var_current), done(this); | |
| 456 | |
| 457 var_current.Bind( | |
| 458 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset)); | |
| 459 Branch(IsUndefined(var_current.value()), &empty, &loop); | |
| 460 | |
| 461 Bind(&empty); | |
| 462 { | |
| 463 StoreObjectField(generator, JSAsyncGeneratorObject::kQueueOffset, request); | |
| 464 Goto(&done); | |
| 465 } | |
| 466 | |
| 467 Bind(&loop); | |
| 468 { | |
| 469 Label loop_next(this), next_empty(this); | |
| 470 Node* current = var_current.value(); | |
| 471 Node* next = LoadObjectField(current, AsyncGeneratorRequest::kNextOffset); | |
| 472 | |
| 473 Branch(IsUndefined(next), &next_empty, &loop_next); | |
| 474 Bind(&next_empty); | |
| 475 { | |
| 476 StoreObjectField(current, AsyncGeneratorRequest::kNextOffset, request); | |
| 477 Goto(&done); | |
| 478 } | |
| 479 | |
| 480 Bind(&loop_next); | |
| 481 { | |
| 482 var_current.Bind(next); | |
| 483 Goto(&loop); | |
| 484 } | |
| 485 } | |
| 486 Bind(&done); | |
| 487 } | |
| 488 | |
| 489 Node* AsyncBuiltinsAssembler::TakeFirstAsyncGeneratorRequestFromQueue( | |
| 490 Node* generator) { | |
| 491 // Removes and returns the first AsyncGeneratorRequest from a | |
| 492 // JSAsyncGeneratorObject's queue. Asserts that the queue is not empty. | |
| 493 CSA_SLOW_ASSERT(this, | |
| 494 HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE)); | |
| 495 | |
| 496 Node* request = | |
| 497 LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset); | |
| 498 CSA_SLOW_ASSERT(this, WordNotEqual(request, UndefinedConstant())); | |
| 499 | |
| 500 Node* next = LoadObjectField(request, AsyncGeneratorRequest::kNextOffset); | |
| 501 | |
| 502 StoreObjectField(generator, JSAsyncGeneratorObject::kQueueOffset, next); | |
| 503 return request; | |
| 504 } | |
| 505 | |
| 506 } // namespace internal | |
| 507 } // namespace v8 | |
| OLD | NEW |