+
+void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack)
+{
+ RefPtr<RegisterID> subject = newTemporary();
+ emitNode(subject.get(), subjectNode);
+ RefPtr<RegisterID> iterator = emitGetById(newTemporary(), subject.get(), propertyNames().iteratorSymbol);
+ {
+ CallArguments args(*this, nullptr);
+ emitMove(args.thisRegister(), subject.get());
+ emitCall(iterator.get(), iterator.get(), NoExpectedFunction, args, node->divot(), node->divotStart(), node->divotEnd());
+ }
+
+ RefPtr<Label> loopDone = newLabel();
+ // RefPtr<Register> iterator's lifetime must be longer than IteratorCloseContext.
+ pushIteratorCloseContext(iterator.get(), node);
+ {
+ LabelScopePtr scope = newLabelScope(LabelScope::Loop);
+ RefPtr<RegisterID> value = newTemporary();
+ emitLoad(value.get(), jsUndefined());
+
+ emitJump(scope->continueTarget());
+
+ RefPtr<Label> loopStart = newLabel();
+ emitLabel(loopStart.get());
+ emitLoopHint();
+
+ RefPtr<Label> tryStartLabel = newLabel();
+ emitLabel(tryStartLabel.get());
+ TryData* tryData = pushTry(tryStartLabel.get());
+ callBack(*this, value.get());
+ emitJump(scope->continueTarget());
+
+ // IteratorClose sequence for throw-ed control flow.
+ {
+ RefPtr<Label> catchHere = emitLabel(newLabel().get());
+ RefPtr<RegisterID> exceptionRegister = newTemporary();
+ RefPtr<RegisterID> thrownValueRegister = newTemporary();
+ popTryAndEmitCatch(tryData, exceptionRegister.get(),
+ thrownValueRegister.get(), catchHere.get(), HandlerType::SynthesizedFinally);
+
+ RefPtr<Label> catchDone = newLabel();
+
+ RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword);
+ emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), catchDone.get());
+
+ RefPtr<Label> returnCallTryStart = newLabel();
+ emitLabel(returnCallTryStart.get());
+ TryData* returnCallTryData = pushTry(returnCallTryStart.get());
+
+ CallArguments returnArguments(*this, nullptr);
+ emitMove(returnArguments.thisRegister(), iterator.get());
+ emitCall(value.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd());
+
+ emitLabel(catchDone.get());
+ emitThrow(exceptionRegister.get());
+
+ // Absorb exception.
+ popTryAndEmitCatch(returnCallTryData, newTemporary(),
+ newTemporary(), catchDone.get(), HandlerType::SynthesizedFinally);
+ emitThrow(exceptionRegister.get());
+ }
+
+ emitLabel(scope->continueTarget());
+ {
+ emitIteratorNext(value.get(), iterator.get(), node);
+ emitJumpIfTrue(emitGetById(newTemporary(), value.get(), propertyNames().done), loopDone.get());
+ emitGetById(value.get(), value.get(), propertyNames().value);
+ emitJump(loopStart.get());
+ }
+
+ emitLabel(scope->breakTarget());
+ }
+
+ // IteratorClose sequence for break-ed control flow.
+ popIteratorCloseContext();
+ emitIteratorClose(iterator.get(), node);
+ emitLabel(loopDone.get());
+}
+
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+RegisterID* BytecodeGenerator::emitGetTemplateObject(RegisterID* dst, TaggedTemplateNode* taggedTemplate)
+{
+ TemplateRegistryKey::StringVector rawStrings;
+ TemplateRegistryKey::StringVector cookedStrings;
+
+ TemplateStringListNode* templateString = taggedTemplate->templateLiteral()->templateStrings();
+ for (; templateString; templateString = templateString->next()) {
+ rawStrings.append(templateString->value()->raw().impl());
+ cookedStrings.append(templateString->value()->cooked().impl());
+ }
+
+ RefPtr<RegisterID> getTemplateObject = nullptr;
+ Variable var = variable(propertyNames().getTemplateObjectPrivateName);
+ if (RegisterID* local = var.local())
+ getTemplateObject = emitMove(newTemporary(), local);
+ else {
+ getTemplateObject = newTemporary();
+ RefPtr<RegisterID> scope = newTemporary();
+ moveToDestinationIfNeeded(scope.get(), emitResolveScope(scope.get(), var));
+ emitGetFromScope(getTemplateObject.get(), scope.get(), var, ThrowIfNotFound);
+ }
+
+ CallArguments arguments(*this, nullptr);
+ emitLoad(arguments.thisRegister(), JSValue(addTemplateRegistryKeyConstant(TemplateRegistryKey(rawStrings, cookedStrings))));
+ return emitCall(dst, getTemplateObject.get(), NoExpectedFunction, arguments, taggedTemplate->divot(), taggedTemplate->divotStart(), taggedTemplate->divotEnd());
+}
+#endif
+
+RegisterID* BytecodeGenerator::emitGetEnumerableLength(RegisterID* dst, RegisterID* base)
+{
+ emitOpcode(op_get_enumerable_length);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitHasGenericProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName)
+{
+ emitOpcode(op_has_generic_property);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ instructions().append(propertyName->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitHasIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName)
+{
+ UnlinkedArrayProfile arrayProfile = newArrayProfile();
+ emitOpcode(op_has_indexed_property);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ instructions().append(propertyName->index());
+ instructions().append(arrayProfile);
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitHasStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator)
+{
+ emitOpcode(op_has_structure_property);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ instructions().append(propertyName->index());
+ instructions().append(enumerator->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitGetPropertyEnumerator(RegisterID* dst, RegisterID* base)
+{
+ emitOpcode(op_get_property_enumerator);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitEnumeratorStructurePropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index)
+{
+ emitOpcode(op_enumerator_structure_pname);
+ instructions().append(dst->index());
+ instructions().append(enumerator->index());
+ instructions().append(index->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitEnumeratorGenericPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index)
+{
+ emitOpcode(op_enumerator_generic_pname);
+ instructions().append(dst->index());
+ instructions().append(enumerator->index());
+ instructions().append(index->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitToIndexString(RegisterID* dst, RegisterID* index)
+{
+ emitOpcode(op_to_index_string);
+ instructions().append(dst->index());
+ instructions().append(index->index());
+ return dst;
+}
+
+
+RegisterID* BytecodeGenerator::emitIsObject(RegisterID* dst, RegisterID* src)
+{
+ emitOpcode(op_is_object);
+ instructions().append(dst->index());
+ instructions().append(src->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitIsUndefined(RegisterID* dst, RegisterID* src)
+{
+ emitOpcode(op_is_undefined);
+ instructions().append(dst->index());
+ instructions().append(src->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node)
+{
+ {
+ RefPtr<RegisterID> next = emitGetById(newTemporary(), iterator, propertyNames().next);
+ CallArguments nextArguments(*this, nullptr);
+ emitMove(nextArguments.thisRegister(), iterator);
+ emitCall(dst, next.get(), NoExpectedFunction, nextArguments, node->divot(), node->divotStart(), node->divotEnd());
+ }
+ {
+ RefPtr<Label> typeIsObject = newLabel();
+ emitJumpIfTrue(emitIsObject(newTemporary(), dst), typeIsObject.get());
+ emitThrowTypeError(ASCIILiteral("Iterator result interface is not an object."));
+ emitLabel(typeIsObject.get());
+ }
+ return dst;
+}
+
+void BytecodeGenerator::emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node)
+{
+ RefPtr<Label> done = newLabel();
+ RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator, propertyNames().returnKeyword);
+ emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), done.get());
+
+ RefPtr<RegisterID> value = newTemporary();
+ CallArguments returnArguments(*this, nullptr);
+ emitMove(returnArguments.thisRegister(), iterator);
+ emitCall(value.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd());
+ emitJumpIfTrue(emitIsObject(newTemporary(), value.get()), done.get());
+ emitThrowTypeError(ASCIILiteral("Iterator result interface is not an object."));
+ emitLabel(done.get());
+}
+
+void BytecodeGenerator::pushIndexedForInScope(RegisterID* localRegister, RegisterID* indexRegister)
+{
+ if (!localRegister)
+ return;
+ m_forInContextStack.append(std::make_unique<IndexedForInContext>(localRegister, indexRegister));
+}
+
+void BytecodeGenerator::popIndexedForInScope(RegisterID* localRegister)
+{
+ if (!localRegister)
+ return;
+ m_forInContextStack.removeLast();
+}
+
+void BytecodeGenerator::pushStructureForInScope(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister)
+{
+ if (!localRegister)
+ return;
+ m_forInContextStack.append(std::make_unique<StructureForInContext>(localRegister, indexRegister, propertyRegister, enumeratorRegister));
+}
+
+void BytecodeGenerator::popStructureForInScope(RegisterID* localRegister)
+{
+ if (!localRegister)
+ return;
+ m_forInContextStack.removeLast();
+}
+
+void BytecodeGenerator::invalidateForInContextForLocal(RegisterID* localRegister)
+{
+ // Lexically invalidating ForInContexts is kind of weak sauce, but it only occurs if
+ // either of the following conditions is true:
+ //
+ // (1) The loop iteration variable is re-assigned within the body of the loop.
+ // (2) The loop iteration variable is captured in the lexical scope of the function.
+ //
+ // These two situations occur sufficiently rarely that it's okay to use this style of
+ // "analysis" to make iteration faster. If we didn't want to do this, we would either have
+ // to perform some flow-sensitive analysis to see if/when the loop iteration variable was
+ // reassigned, or we'd have to resort to runtime checks to see if the variable had been
+ // reassigned from its original value.
+ for (size_t i = m_forInContextStack.size(); i > 0; i--) {
+ ForInContext* context = m_forInContextStack[i - 1].get();
+ if (context->local() != localRegister)
+ continue;
+ context->invalidate();
+ break;
+ }
+}