summaryrefslogtreecommitdiff
path: root/deps/v8/src/interpreter/bytecode-generator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/interpreter/bytecode-generator.cc')
-rw-r--r--deps/v8/src/interpreter/bytecode-generator.cc400
1 files changed, 253 insertions, 147 deletions
diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc
index 45f0d1eca9..ee94e7a2e2 100644
--- a/deps/v8/src/interpreter/bytecode-generator.cc
+++ b/deps/v8/src/interpreter/bytecode-generator.cc
@@ -835,6 +835,24 @@ class BytecodeGenerator::FeedbackSlotCache : public ZoneObject {
ZoneMap<Key, FeedbackSlot> map_;
};
+class BytecodeGenerator::IteratorRecord final {
+ public:
+ IteratorRecord(Register object_register, Register next_register,
+ IteratorType type = IteratorType::kNormal)
+ : type_(type), object_(object_register), next_(next_register) {
+ DCHECK(object_.is_valid() && next_.is_valid());
+ }
+
+ inline IteratorType type() const { return type_; }
+ inline Register object() const { return object_; }
+ inline Register next() const { return next_; }
+
+ private:
+ IteratorType type_;
+ Register object_;
+ Register next_;
+};
+
BytecodeGenerator::BytecodeGenerator(
CompilationInfo* info, const AstStringConstants* ast_string_constants)
: zone_(info->zone()),
@@ -1130,7 +1148,7 @@ void BytecodeGenerator::VisitIterationHeader(int first_suspend_id,
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &not_resuming);
// Otherwise this is an error.
- builder()->Abort(BailoutReason::kInvalidJumpTableIndex);
+ builder()->Abort(AbortReason::kInvalidJumpTableIndex);
builder()->Bind(&not_resuming);
}
@@ -1162,7 +1180,7 @@ void BytecodeGenerator::BuildGeneratorPrologue() {
}
// We fall through when the generator state is not in the jump table.
// TODO(leszeks): Only generate this for debug builds.
- builder()->Abort(BailoutReason::kInvalidJumpTableIndex);
+ builder()->Abort(AbortReason::kInvalidJumpTableIndex);
// This is a regular call.
builder()
@@ -1674,6 +1692,7 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
builder()->SetExpressionAsStatementPosition(stmt->assign_iterator());
VisitForEffect(stmt->assign_iterator());
+ VisitForEffect(stmt->assign_next());
VisitIterationHeader(stmt, &loop_builder);
builder()->SetExpressionAsStatementPosition(stmt->next_result());
@@ -1712,9 +1731,11 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
}
try_control_builder.EndTry();
- // Create a catch scope that binds the exception.
- BuildNewLocalCatchContext(stmt->scope());
- builder()->StoreAccumulatorInRegister(context);
+ if (stmt->scope()) {
+ // Create a catch scope that binds the exception.
+ BuildNewLocalCatchContext(stmt->scope());
+ builder()->StoreAccumulatorInRegister(context);
+ }
// If requested, clear message object as we enter the catch block.
if (stmt->ShouldClearPendingException(outer_catch_prediction)) {
@@ -1725,7 +1746,11 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
builder()->LoadAccumulatorWithRegister(context);
// Evaluate the catch-block.
- VisitInScope(stmt->catch_block(), stmt->scope());
+ if (stmt->scope()) {
+ VisitInScope(stmt->catch_block(), stmt->scope());
+ } else {
+ VisitBlock(stmt->catch_block());
+ }
try_control_builder.EndCatch();
}
@@ -2069,6 +2094,8 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
}
void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
+ expr->InitDepthAndFlags();
+
// Fast path for the empty object literal which doesn't need an
// AllocationSite.
if (expr->IsEmptyObjectLiteral()) {
@@ -2275,6 +2302,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
+ expr->InitDepthAndFlags();
+
// Deep-copy the literal boilerplate.
int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
if (expr->is_empty()) {
@@ -2290,31 +2319,25 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
builder()->CreateArrayLiteral(entry, literal_index, flags);
array_literals_.push_back(std::make_pair(expr, entry));
- Register index, literal;
+ Register index = register_allocator()->NewRegister();
+ Register literal = register_allocator()->NewRegister();
+ builder()->StoreAccumulatorInRegister(literal);
// We'll reuse the same literal slot for all of the non-constant
// subexpressions that use a keyed store IC.
// Evaluate all the non-constant subexpressions and store them into the
// newly cloned array.
- bool literal_in_accumulator = true;
FeedbackSlot slot;
- for (int array_index = 0; array_index < expr->values()->length();
- array_index++) {
- Expression* subexpr = expr->values()->at(array_index);
- if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
+ int array_index = 0;
+ ZoneList<Expression*>::iterator iter = expr->BeginValue();
+ for (; iter != expr->FirstSpreadOrEndValue(); ++iter, array_index++) {
+ Expression* subexpr = *iter;
DCHECK(!subexpr->IsSpread());
-
- if (literal_in_accumulator) {
- index = register_allocator()->NewRegister();
- literal = register_allocator()->NewRegister();
- builder()->StoreAccumulatorInRegister(literal);
- literal_in_accumulator = false;
- }
+ if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
if (slot.IsInvalid()) {
slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
}
-
builder()
->LoadLiteral(Smi::FromInt(array_index))
.StoreAccumulatorInRegister(index);
@@ -2323,10 +2346,68 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
language_mode());
}
- if (!literal_in_accumulator) {
- // Restore literal array into accumulator.
- builder()->LoadAccumulatorWithRegister(literal);
+ // Handle spread elements and elements following.
+ for (; iter != expr->EndValue(); ++iter) {
+ Expression* subexpr = *iter;
+ if (subexpr->IsSpread()) {
+ BuildArrayLiteralSpread(subexpr->AsSpread(), literal);
+ } else if (!subexpr->IsTheHoleLiteral()) {
+ // Perform %AppendElement(array, <subexpr>)
+ RegisterAllocationScope register_scope(this);
+ RegisterList args = register_allocator()->NewRegisterList(2);
+ builder()->MoveRegister(literal, args[0]);
+ VisitForRegisterValue(subexpr, args[1]);
+ builder()->CallRuntime(Runtime::kAppendElement, args);
+ } else {
+ // Peform ++<array>.length;
+ // TODO(caitp): Why can't we just %AppendElement(array, <The Hole>?)
+ auto length = ast_string_constants()->length_string();
+ builder()->LoadNamedProperty(
+ literal, length, feedback_index(feedback_spec()->AddLoadICSlot()));
+ builder()->UnaryOperation(
+ Token::INC, feedback_index(feedback_spec()->AddBinaryOpICSlot()));
+ builder()->StoreNamedProperty(
+ literal, length,
+ feedback_index(
+ feedback_spec()->AddStoreICSlot(LanguageMode::kStrict)),
+ LanguageMode::kStrict);
+ }
}
+
+ // Restore literal array into accumulator.
+ builder()->LoadAccumulatorWithRegister(literal);
+}
+
+void BytecodeGenerator::BuildArrayLiteralSpread(Spread* spread,
+ Register array) {
+ RegisterAllocationScope register_scope(this);
+ RegisterList args = register_allocator()->NewRegisterList(2);
+ builder()->MoveRegister(array, args[0]);
+ Register next_result = args[1];
+
+ builder()->SetExpressionAsStatementPosition(spread->expression());
+ IteratorRecord iterator =
+ BuildGetIteratorRecord(spread->expression(), IteratorType::kNormal);
+ LoopBuilder loop_builder(builder(), nullptr, nullptr);
+ loop_builder.LoopHeader();
+
+ // Call the iterator's .next() method. Break from the loop if the `done`
+ // property is truthy, otherwise load the value from the iterator result and
+ // append the argument.
+ BuildIteratorNext(iterator, next_result);
+ builder()->LoadNamedProperty(
+ next_result, ast_string_constants()->done_string(),
+ feedback_index(feedback_spec()->AddLoadICSlot()));
+ loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
+
+ loop_builder.LoopBody();
+ builder()
+ ->LoadNamedProperty(next_result, ast_string_constants()->value_string(),
+ feedback_index(feedback_spec()->AddLoadICSlot()))
+ .StoreAccumulatorInRegister(args[1])
+ .CallRuntime(Runtime::kAppendElement, args);
+ loop_builder.BindContinueTarget();
+ loop_builder.JumpToHeader(loop_depth_);
}
void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
@@ -2557,8 +2638,7 @@ void BytecodeGenerator::BuildVariableAssignment(
// TODO(ishell): consider using FeedbackSlotCache for variables here.
FeedbackSlot slot =
feedback_spec()->AddStoreGlobalICSlot(language_mode());
- builder()->StoreGlobal(variable->raw_name(), feedback_index(slot),
- language_mode());
+ builder()->StoreGlobal(variable->raw_name(), feedback_index(slot));
break;
}
case VariableLocation::CONTEXT: {
@@ -2787,7 +2867,7 @@ void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) {
// accumulator. When the generator is resumed, the sent value is loaded in the
// accumulator.
void BytecodeGenerator::BuildSuspendPoint(int suspend_id) {
- RegisterList registers(0, register_allocator()->next_register_index());
+ RegisterList registers = register_allocator()->AllLiveRegisters();
// Save context, registers, and state. Then return.
builder()->SuspendGenerator(generator_object(), registers, suspend_id);
@@ -2798,19 +2878,10 @@ void BytecodeGenerator::BuildSuspendPoint(int suspend_id) {
// Upon resume, we continue here.
builder()->Bind(generator_jump_table_, suspend_id);
- // Clobbers all registers.
- builder()->RestoreGeneratorRegisters(generator_object(), registers);
-
- // Update state to indicate that we have finished resuming. Loop headers
- // rely on this.
- builder()
- ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))
- .StoreAccumulatorInRegister(generator_state_);
-
- // When resuming execution of a generator, module or async function, the sent
- // value is in the [[input_or_debug_pos]] slot.
- builder()->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos,
- generator_object());
+ // Clobbers all registers, updating the state to indicate that we have
+ // finished resuming and setting the accumulator to the [[input_or_debug_pos]]
+ // slot of the generator object.
+ builder()->ResumeGenerator(generator_object(), generator_state_, registers);
}
void BytecodeGenerator::VisitYield(Yield* expr) {
@@ -2903,7 +2974,9 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
//
// let output; // uninitialized
//
-// let iterator = GetIterator(iterable);
+// let iteratorRecord = GetIterator(iterable);
+// let iterator = iteratorRecord.[[Iterator]];
+// let next = iteratorRecord.[[NextMethod]];
// let input = undefined;
// let resumeMode = kNext;
//
@@ -2912,25 +2985,25 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
// // Forward input according to resumeMode and obtain output.
// switch (resumeMode) {
// case kNext:
-// output = iterator.next(input);
+// output = next.[[Call]](iterator, « »);;
// break;
// case kReturn:
// let iteratorReturn = iterator.return;
// if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return input;
-// output = %_Call(iteratorReturn, iterator, input);
+// output = iteratorReturn.[[Call]](iterator, «input»);
// break;
// case kThrow:
// let iteratorThrow = iterator.throw;
// if (IS_NULL_OR_UNDEFINED(iteratorThrow)) {
// let iteratorReturn = iterator.return;
// if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
-// output = %_Call(iteratorReturn, iterator);
+// output = iteratorReturn.[[Call]](iterator, « »);
// if (IS_ASYNC_GENERATOR) output = await output;
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
// }
// throw MakeTypeError(kThrowMethodMissing);
// }
-// output = %_Call(iteratorThrow, iterator, input);
+// output = iteratorThrow.[[Call]](iterator, «input»);
// break;
// }
//
@@ -2963,13 +3036,12 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
{
RegisterAllocationScope register_scope(this);
-
RegisterList iterator_and_input = register_allocator()->NewRegisterList(2);
+ IteratorRecord iterator = BuildGetIteratorRecord(
+ expr->expression(),
+ register_allocator()->NewRegister() /* next method */,
+ iterator_and_input[0], iterator_type);
- Register iterator = iterator_and_input[0];
-
- BuildGetIterator(expr->expression(), iterator_type);
- builder()->StoreAccumulatorInRegister(iterator);
Register input = iterator_and_input[1];
builder()->LoadUndefined().StoreAccumulatorInRegister(input);
builder()
@@ -3000,109 +3072,46 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
// {JSGeneratorObject::kNext} in this case.
STATIC_ASSERT(JSGeneratorObject::kNext == 0);
{
- RegisterAllocationScope register_scope(this);
- // output = iterator.next(input);
- Register iterator_next = register_allocator()->NewRegister();
- FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
- FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
- builder()
- ->LoadNamedProperty(iterator,
- ast_string_constants()->next_string(),
- feedback_index(load_slot))
- .StoreAccumulatorInRegister(iterator_next)
- .CallProperty(iterator_next, iterator_and_input,
- feedback_index(call_slot))
- .Jump(after_switch.New());
+ FeedbackSlot slot = feedback_spec()->AddCallICSlot();
+ builder()->CallProperty(iterator.next(), iterator_and_input,
+ feedback_index(slot));
+ builder()->Jump(after_switch.New());
}
STATIC_ASSERT(JSGeneratorObject::kReturn == 1);
builder()->Bind(switch_jump_table, JSGeneratorObject::kReturn);
{
- RegisterAllocationScope register_scope(this);
- BytecodeLabels return_input(zone());
- // Trigger return from within the inner iterator.
- Register iterator_return = register_allocator()->NewRegister();
- FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
- FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
- builder()
- ->LoadNamedProperty(iterator,
- ast_string_constants()->return_string(),
- feedback_index(load_slot))
- .JumpIfUndefined(return_input.New())
- .JumpIfNull(return_input.New())
- .StoreAccumulatorInRegister(iterator_return)
- .CallProperty(iterator_return, iterator_and_input,
- feedback_index(call_slot))
- .Jump(after_switch.New());
-
- return_input.Bind(builder());
- {
- builder()->LoadAccumulatorWithRegister(input);
- if (iterator_type == IteratorType::kAsync) {
- execution_control()->AsyncReturnAccumulator();
- } else {
- execution_control()->ReturnAccumulator();
- }
+ const AstRawString* return_string =
+ ast_string_constants()->return_string();
+ BytecodeLabels no_return_method(zone());
+
+ BuildCallIteratorMethod(iterator.object(), return_string,
+ iterator_and_input, after_switch.New(),
+ &no_return_method);
+ no_return_method.Bind(builder());
+ builder()->LoadAccumulatorWithRegister(input);
+ if (iterator_type == IteratorType::kAsync) {
+ execution_control()->AsyncReturnAccumulator();
+ } else {
+ execution_control()->ReturnAccumulator();
}
}
STATIC_ASSERT(JSGeneratorObject::kThrow == 2);
builder()->Bind(switch_jump_table, JSGeneratorObject::kThrow);
{
- BytecodeLabels iterator_throw_is_undefined(zone());
- {
- RegisterAllocationScope register_scope(this);
- // If the inner iterator has a throw method, use it to trigger an
- // exception inside.
- Register iterator_throw = register_allocator()->NewRegister();
- FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
- FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
- builder()
- ->LoadNamedProperty(iterator,
- ast_string_constants()->throw_string(),
- feedback_index(load_slot))
- .JumpIfUndefined(iterator_throw_is_undefined.New())
- .JumpIfNull(iterator_throw_is_undefined.New())
- .StoreAccumulatorInRegister(iterator_throw);
- builder()
- ->CallProperty(iterator_throw, iterator_and_input,
- feedback_index(call_slot))
- .Jump(after_switch.New());
- }
-
- iterator_throw_is_undefined.Bind(builder());
- {
- RegisterAllocationScope register_scope(this);
- BytecodeLabels throw_throw_method_missing(zone());
- Register iterator_return = register_allocator()->NewRegister();
- // If iterator.throw does not exist, try to use iterator.return to
- // inform the iterator that it should stop.
- FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
- FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
- builder()
- ->LoadNamedProperty(iterator,
- ast_string_constants()->return_string(),
- feedback_index(load_slot))
- .StoreAccumulatorInRegister(iterator_return);
- builder()
- ->JumpIfUndefined(throw_throw_method_missing.New())
- .JumpIfNull(throw_throw_method_missing.New())
- .CallProperty(iterator_return, RegisterList(iterator),
- feedback_index(call_slot));
-
- if (iterator_type == IteratorType::kAsync) {
- // For async generators, await the result of the .return() call.
- BuildAwait(expr->await_iterator_close_suspend_id());
- builder()->StoreAccumulatorInRegister(output);
- }
-
- builder()
- ->JumpIfJSReceiver(throw_throw_method_missing.New())
- .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, output);
-
- throw_throw_method_missing.Bind(builder());
- builder()->CallRuntime(Runtime::kThrowThrowMethodMissing);
- }
+ const AstRawString* throw_string =
+ ast_string_constants()->throw_string();
+ BytecodeLabels no_throw_method(zone());
+ BuildCallIteratorMethod(iterator.object(), throw_string,
+ iterator_and_input, after_switch.New(),
+ &no_throw_method);
+
+ // If there is no "throw" method, perform IteratorClose, and finally
+ // throw a TypeError.
+ no_throw_method.Bind(builder());
+ BuildIteratorClose(iterator, expr->await_iterator_close_suspend_id());
+ builder()->CallRuntime(Runtime::kThrowThrowMethodMissing);
}
after_switch.Bind(builder());
@@ -3355,6 +3364,11 @@ void BytecodeGenerator::VisitProperty(Property* expr) {
}
}
+void BytecodeGenerator::VisitResolvedProperty(ResolvedProperty* expr) {
+ // Handled by VisitCall().
+ UNREACHABLE();
+}
+
void BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args,
RegisterList* arg_regs) {
// Visit arguments.
@@ -3397,6 +3411,13 @@ void BytecodeGenerator::VisitCall(Call* expr) {
VisitPropertyLoadForRegister(args.last_register(), property, callee);
break;
}
+ case Call::RESOLVED_PROPERTY_CALL: {
+ ResolvedProperty* resolved = callee_expr->AsResolvedProperty();
+ VisitAndPushIntoRegisterList(resolved->object(), &args);
+ VisitForAccumulatorValue(resolved->property());
+ builder()->StoreAccumulatorInRegister(callee);
+ break;
+ }
case Call::GLOBAL_CALL: {
// Receiver is undefined for global calls.
if (!is_spread_call) {
@@ -3421,16 +3442,15 @@ void BytecodeGenerator::VisitCall(Call* expr) {
Register name = register_allocator()->NewRegister();
// Call %LoadLookupSlotForCall to get the callee and receiver.
- DCHECK(Register::AreContiguous(callee, receiver));
- RegisterList result_pair(callee.index(), 2);
- USE(receiver);
-
+ RegisterList result_pair = register_allocator()->NewRegisterList(2);
Variable* variable = callee_expr->AsVariableProxy()->var();
builder()
->LoadLiteral(variable->raw_name())
.StoreAccumulatorInRegister(name)
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name,
- result_pair);
+ result_pair)
+ .MoveRegister(result_pair[0], callee)
+ .MoveRegister(result_pair[1], receiver);
}
break;
}
@@ -3506,7 +3526,8 @@ void BytecodeGenerator::VisitCall(Call* expr) {
DCHECK(!implicit_undefined_receiver);
builder()->CallWithSpread(callee, args, feedback_slot_index);
} else if (call_type == Call::NAMED_PROPERTY_CALL ||
- call_type == Call::KEYED_PROPERTY_CALL) {
+ call_type == Call::KEYED_PROPERTY_CALL ||
+ call_type == Call::RESOLVED_PROPERTY_CALL) {
DCHECK(!implicit_undefined_receiver);
builder()->CallProperty(callee, args, feedback_slot_index);
} else if (implicit_undefined_receiver) {
@@ -4075,6 +4096,91 @@ void BytecodeGenerator::BuildGetIterator(Expression* iterable,
}
}
+// Returns an IteratorRecord which is valid for the lifetime of the current
+// register_allocation_scope.
+BytecodeGenerator::IteratorRecord BytecodeGenerator::BuildGetIteratorRecord(
+ Expression* iterable, Register next, Register object, IteratorType hint) {
+ DCHECK(next.is_valid() && object.is_valid());
+ BuildGetIterator(iterable, hint);
+
+ builder()
+ ->StoreAccumulatorInRegister(object)
+ .LoadNamedProperty(object, ast_string_constants()->next_string(),
+ feedback_index(feedback_spec()->AddLoadICSlot()))
+ .StoreAccumulatorInRegister(next);
+ return IteratorRecord(object, next, hint);
+}
+
+BytecodeGenerator::IteratorRecord BytecodeGenerator::BuildGetIteratorRecord(
+ Expression* iterable, IteratorType hint) {
+ Register next = register_allocator()->NewRegister();
+ Register object = register_allocator()->NewRegister();
+ return BuildGetIteratorRecord(iterable, next, object, hint);
+}
+
+void BytecodeGenerator::BuildIteratorNext(const IteratorRecord& iterator,
+ Register next_result) {
+ DCHECK(next_result.is_valid());
+ builder()->CallProperty(iterator.next(), RegisterList(iterator.object()),
+ feedback_index(feedback_spec()->AddCallICSlot()));
+
+ // TODO(caitp): support async IteratorNext here.
+
+ BytecodeLabel is_object;
+ builder()
+ ->StoreAccumulatorInRegister(next_result)
+ .JumpIfJSReceiver(&is_object)
+ .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, next_result)
+ .Bind(&is_object);
+}
+
+void BytecodeGenerator::BuildCallIteratorMethod(Register iterator,
+ const AstRawString* method_name,
+ RegisterList receiver_and_args,
+ BytecodeLabel* if_called,
+ BytecodeLabels* if_notcalled) {
+ RegisterAllocationScope register_scope(this);
+
+ Register method = register_allocator()->NewRegister();
+ FeedbackSlot slot = feedback_spec()->AddLoadICSlot();
+ builder()
+ ->LoadNamedProperty(iterator, method_name, feedback_index(slot))
+ .JumpIfUndefined(if_notcalled->New())
+ .JumpIfNull(if_notcalled->New())
+ .StoreAccumulatorInRegister(method)
+ .CallProperty(method, receiver_and_args,
+ feedback_index(feedback_spec()->AddCallICSlot()))
+ .Jump(if_called);
+}
+
+void BytecodeGenerator::BuildIteratorClose(const IteratorRecord& iterator,
+ int suspend_id) {
+ RegisterAllocationScope register_scope(this);
+ BytecodeLabels done(zone());
+ BytecodeLabel if_called;
+ RegisterList args = RegisterList(iterator.object());
+ BuildCallIteratorMethod(iterator.object(),
+ ast_string_constants()->return_string(), args,
+ &if_called, &done);
+ builder()->Bind(&if_called);
+
+ if (iterator.type() == IteratorType::kAsync) {
+ DCHECK_GE(suspend_id, 0);
+ BuildAwait(suspend_id);
+ }
+
+ builder()->JumpIfJSReceiver(done.New());
+ {
+ RegisterAllocationScope register_scope(this);
+ Register return_result = register_allocator()->NewRegister();
+ builder()
+ ->StoreAccumulatorInRegister(return_result)
+ .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, return_result);
+ }
+
+ done.Bind(builder());
+}
+
void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
builder()->SetExpressionPosition(expr);
BuildGetIterator(expr->iterable(), expr->hint());