escargot/src/interpreter/ByteCodeGenerator.cpp
Seonghyun Kim e7221f4211 Fix labeled continue targeting a for-of loop (Issue #1577 Crash #1)
`L: for (const v of [...]) { continue L; }` aborted with
Assertion `!v.isEmpty()' failed, and `continue OUTER` from a nested
loop silently terminated the script.

A `continue <label>` whose label targets a for-of loop was left to be
resolved by LabelledStatementNode after the loop body, by which point
the for-of iterator-cleanup try block had registered the jump as a
complex case. It was then morphed into a JumpComplexCase that unwound
the try block, wrongly closing the iterator and leaving an empty Value
in the result register.

A previous per-loop attempt (8fd141b2) was reverted (60b1202a) because
a single m_currentLoopLabel leaked into nested loops and broke test262.

Track all labels directly targeting a loop (m_currentLoopLabels), clear
the list when entering each loop body so nested loops never inherit it,
and let for-of/for-in resolve continues for its own labels to
continuePosition (a plain jump, identical to an unlabeled continue)
before the try block is registered as a complex case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
2026-06-17 10:06:57 +09:00

966 lines
50 KiB
C++

/*
* Copyright (c) 2016-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "Escargot.h"
#include "ByteCodeGenerator.h"
#include "runtime/VMInstance.h"
#include "interpreter/ByteCode.h"
#include "parser/ast/AST.h"
#include "parser/CodeBlock.h"
#include "debugger/Debugger.h"
#if defined(ENABLE_CODE_CACHE)
#include "codecache/CodeCache.h"
#endif
namespace Escargot {
ByteCodeGenerateContext::ByteCodeGenerateContext(InterpretedCodeBlock* codeBlock, ByteCodeBlock* byteCodeBlock, bool isGlobalScope, bool isEvalCode, bool isWithScope, void* numeralLiteralData)
: m_baseRegisterCount(0)
, m_codeBlock(codeBlock)
, m_byteCodeBlock(byteCodeBlock)
, m_locData(nullptr)
, m_isGlobalScope(isGlobalScope)
, m_isEvalCode(isEvalCode)
, m_isOutermostContext(true)
, m_isWithScope(isWithScope)
, m_isFunctionDeclarationBindingInitialization(false)
, m_isVarDeclaredBindingInitialization(false)
, m_isLexicallyDeclaredBindingInitialization(false)
, m_isUsingBindingInitialization(false)
, m_isAwaitUsingBindingInitialization(false)
, m_canSkipCopyToRegister(true)
, m_keepNumberalLiteralsInRegisterFile(numeralLiteralData)
, m_inCallingExpressionScope(false)
, m_inObjectDestruction(false)
, m_inParameterInitialization(false)
, m_isHeadOfMemberExpression(false)
, m_forInOfVarBinding(false)
, m_isLeftBindingAffectedByRightExpression(false)
#if defined(ENABLE_TCO)
, m_tcoDisabled(false)
#endif
, m_needsExtendedExecutionState(codeBlock->isAsync() || codeBlock->isGenerator())
, m_registerStack(new std::vector<ByteCodeRegisterIndex>())
, m_disposableRecordRegisterStack(new std::vector<ByteCodeRegisterIndex>())
, m_lexicallyDeclaredNames(new std::vector<std::pair<size_t, AtomicString>>())
, m_positionToContinue(0)
, m_lexicalBlockIndex(0)
, m_classInfo()
, m_numeralLiteralData(numeralLiteralData) // should be NumeralLiteralVector
#if defined(ENABLE_TCO)
, m_returnRegister(SIZE_MAX)
#endif
#ifdef ESCARGOT_DEBUGGER
, m_breakpointContext(nullptr)
#endif /* ESCARGOT_DEBUGGER */
{
}
void ByteCodeGenerateContext::consumeLabelledContinuePositions(ByteCodeBlock* cb, size_t position, String* lbl, int outerLimitCount)
{
for (size_t i = 0; i < m_labelledContinueStatmentPositions.size(); i++) {
if (*m_labelledContinueStatmentPositions[i].first == *lbl) {
Jump* shouldBeJump = cb->peekCode<Jump>(m_labelledContinueStatmentPositions[i].second);
ASSERT(shouldBeJump->m_orgOpcode == JumpOpcode);
shouldBeJump->m_jumpPosition = position;
morphJumpPositionIntoComplexCase(cb, m_labelledContinueStatmentPositions[i].second, outerLimitCount);
m_labelledContinueStatmentPositions.erase(m_labelledContinueStatmentPositions.begin() + i);
i = -1;
}
}
}
void ByteCodeGenerateContext::consumeBreakPositions(ByteCodeBlock* cb, size_t position, int outerLimitCount)
{
for (size_t i = 0; i < m_breakStatementPositions.size(); i++) {
Jump* shouldBeJump = cb->peekCode<Jump>(m_breakStatementPositions[i]);
ASSERT(shouldBeJump->m_orgOpcode == JumpOpcode);
shouldBeJump->m_jumpPosition = position;
morphJumpPositionIntoComplexCase(cb, m_breakStatementPositions[i], outerLimitCount);
}
m_breakStatementPositions.clear();
}
void ByteCodeGenerateContext::consumeLabelledBreakPositions(ByteCodeBlock* cb, size_t position, String* lbl, int outerLimitCount)
{
for (size_t i = 0; i < m_labelledBreakStatmentPositions.size(); i++) {
if (*m_labelledBreakStatmentPositions[i].first == *lbl) {
Jump* shouldBeJump = cb->peekCode<Jump>(m_labelledBreakStatmentPositions[i].second);
ASSERT(shouldBeJump->m_orgOpcode == JumpOpcode);
shouldBeJump->m_jumpPosition = position;
morphJumpPositionIntoComplexCase(cb, m_labelledBreakStatmentPositions[i].second, outerLimitCount);
m_labelledBreakStatmentPositions.erase(m_labelledBreakStatmentPositions.begin() + i);
i = -1;
}
}
}
void ByteCodeGenerateContext::consumeContinuePositions(ByteCodeBlock* cb, size_t position, int outerLimitCount)
{
for (size_t i = 0; i < m_continueStatementPositions.size(); i++) {
Jump* shouldBeJump = cb->peekCode<Jump>(m_continueStatementPositions[i]);
ASSERT(shouldBeJump->m_orgOpcode == JumpOpcode);
shouldBeJump->m_jumpPosition = position;
morphJumpPositionIntoComplexCase(cb, m_continueStatementPositions[i], outerLimitCount);
}
m_continueStatementPositions.clear();
}
void ByteCodeGenerateContext::morphJumpPositionIntoComplexCase(ByteCodeBlock* cb, size_t codePos, size_t outerLimitCount)
{
auto iter = m_complexCaseStatementPositions.find(codePos);
if (iter != m_complexCaseStatementPositions.end()) {
size_t index = m_byteCodeBlock->m_jumpFlowRecordData.size();
m_byteCodeBlock->m_jumpFlowRecordData.pushBack(JumpFlowRecord((cb->peekCode<Jump>(codePos)->m_jumpPosition), iter->second, outerLimitCount));
new (cb->m_code.data() + codePos) JumpComplexCase(index);
m_complexCaseStatementPositions.erase(iter);
m_needsExtendedExecutionState = true;
}
}
void ByteCodeGenerateContext::linkOptionalChainingJumpPosition(ByteCodeBlock* cb, size_t jumpToPosition)
{
ASSERT(m_optionalChainingJumpPositionLists.size());
std::vector<size_t>& jumpPositions = m_optionalChainingJumpPositionLists.back();
for (size_t i = 0; i < jumpPositions.size(); i++) {
cb->peekCode<JumpIfUndefinedOrNull>(jumpPositions[i])->m_jumpPosition = jumpToPosition;
}
}
#ifdef ESCARGOT_DEBUGGER
void ByteCodeGenerateContext::calculateBreakpointLocation(size_t index, ExtendedNodeLOC sourceElementStart)
{
ASSERT(index >= sourceElementStart.index);
const size_t indexOffset = index - sourceElementStart.index;
size_t lineOffset = m_breakpointContext->m_lastBreakpointLineOffset;
ASSERT(indexOffset >= m_breakpointContext->m_lastBreakpointIndexOffset);
// calculate the current breakpoint's location based on the last breakpoint's location
StringView src = m_codeBlock->src();
for (size_t i = m_breakpointContext->m_lastBreakpointIndexOffset; i < indexOffset; i++) {
char16_t c = src.charAt(i);
if (EscargotLexer::isLineTerminator(c)) {
// skip \r\n
if (UNLIKELY(c == 13 && (i + 1 < indexOffset) && src.charAt(i + 1) == 10)) {
i++;
}
lineOffset++;
}
}
// cache the current breakpoint's calculated location (offset)
m_breakpointContext->m_lastBreakpointIndexOffset = indexOffset;
m_breakpointContext->m_lastBreakpointLineOffset = lineOffset;
}
void ByteCodeGenerateContext::insertBreakpoint(size_t index, Node* node)
{
ASSERT(m_breakpointContext != nullptr);
ASSERT(index != SIZE_MAX);
// do not insert any breakpoint for unmarked code
if (UNLIKELY(!m_codeBlock->markDebugging())) {
return;
}
// dynamically generated code should not insert any debugging code
ASSERT(!m_codeBlock->hasDynamicSourceCode());
// previous breakpoint's line offset
size_t lastLineOffset = m_breakpointContext->m_lastBreakpointLineOffset;
ExtendedNodeLOC sourceElementStart = m_codeBlock->functionStart();
calculateBreakpointLocation(index, sourceElementStart);
// insert a breakpoint if its the first breakpoint insertion or
// there was no breakpoint insertion with the same lineoffset
if ((m_breakpointContext->m_breakpointLocations->breakpointLocations.size() == 0) || (lastLineOffset != m_breakpointContext->m_lastBreakpointLineOffset)) {
ASSERT(lastLineOffset <= m_breakpointContext->m_lastBreakpointLineOffset);
insertBreakpointAt(m_breakpointContext->m_lastBreakpointLineOffset + sourceElementStart.line, node);
}
}
void ByteCodeGenerateContext::insertBreakpointAt(size_t line, Node* node)
{
// add breakpoint only when its line offset is bigger than original source's start line offset
// m_originSourceLineOffset is usually set as 0, but for the manipulated source code case,
// we should consider original source code and insert bytecode only for the original source code case
if (line > m_breakpointContext->m_originSourceLineOffset) {
m_breakpointContext->m_breakpointLocations->breakpointLocations.push_back(Debugger::BreakpointLocation(line, (uint32_t)m_byteCodeBlock->currentCodeSize()));
m_byteCodeBlock->pushCode(BreakpointDisabled(ByteCodeLOC(node->loc().index)), this, node->m_loc.index);
}
}
ByteCodeBreakpointContext::ByteCodeBreakpointContext(Debugger* debugger, InterpretedCodeBlock* codeBlock, bool addBreakpointLocationsInfoToDebugger)
: m_lastBreakpointLineOffset(0)
, m_lastBreakpointIndexOffset(0)
, m_originSourceLineOffset(codeBlock->script()->originSourceLineOffset())
, m_breakpointLocations(nullptr)
, m_sharedWithDebugger(false)
{
m_breakpointLocations = new Debugger::BreakpointLocationsInfo(reinterpret_cast<Debugger::WeakCodeRef*>(codeBlock));
if (debugger && codeBlock->markDebugging() && addBreakpointLocationsInfoToDebugger) {
debugger->appendBreakpointLocations(m_breakpointLocations);
m_sharedWithDebugger = true;
}
}
ByteCodeBreakpointContext::~ByteCodeBreakpointContext()
{
if (!m_sharedWithDebugger) {
// directly delete each BreakpointLocationsInfo
// because BreakpointLocationsInfo is not shared with Debugger
delete m_breakpointLocations;
}
}
#endif /* ESCARGOT_DEBUGGER */
#define ASSIGN_STACKINDEX_IF_NEEDED(registerIndex, stackBase, stackBaseWillBe, stackVariableSize) \
{ \
if (LIKELY(registerIndex != REGISTER_LIMIT)) { \
if (registerIndex >= stackBase) { \
if (registerIndex >= (stackBase + VARIABLE_LIMIT)) { \
registerIndex = stackBaseWillBe + (registerIndex - (stackBase + VARIABLE_LIMIT)) + stackVariableSize; \
} else { \
registerIndex = stackBaseWillBe + (registerIndex - stackBase); \
} \
ASSERT(registerIndex < block->m_requiredTotalRegisterNumber); \
} \
} \
}
const uint8_t byteCodeLengths[] = {
#define ITER_BYTE_CODE(code) \
(uint8_t)sizeof(code),
FOR_EACH_BYTECODE(ITER_BYTE_CODE)
#undef ITER_BYTE_CODE
};
ByteCodeBlock* ByteCodeGenerator::generateByteCode(Context* context, InterpretedCodeBlock* codeBlock, Node* ast, bool inWithFromRuntime, bool cacheByteCode)
{
ASSERT(!codeBlock->byteCodeBlock());
ByteCodeBlock* block = new ByteCodeBlock(codeBlock);
NumeralLiteralVector* nData = nullptr;
if (ast->type() == ASTNodeType::Program) {
nData = &((ProgramNode*)ast)->numeralLiteralVector();
} else {
nData = &((FunctionNode*)ast)->numeralLiteralVector();
}
if (nData->size() == 0) {
nData = nullptr;
}
ByteCodeGenerateContext ctx(codeBlock, block, codeBlock->isGlobalScope(), codeBlock->isEvalCode(), inWithFromRuntime || codeBlock->inWith(), nData);
#ifdef ESCARGOT_DEBUGGER
ByteCodeBreakpointContext breakpointContext(context->debugger(), codeBlock);
ctx.m_breakpointContext = &breakpointContext;
#endif /* ESCARGOT_DEBUGGER */
// generate bytecode
ast->generateStatementByteCode(block, &ctx);
if (ctx.m_keepNumberalLiteralsInRegisterFile) {
block->m_numeralLiteralData.resizeFitWithUninitializedValues(nData->size());
memcpy(block->m_numeralLiteralData.data(), nData->data(), sizeof(Value) * nData->size());
}
block->m_code.shrinkToFit();
block->m_requiredTotalRegisterNumber = block->m_requiredOperandRegisterNumber + codeBlock->totalStackAllocatedVariableSize() + block->m_numeralLiteralData.size();
block->m_needsExtendedExecutionState = ctx.m_needsExtendedExecutionState;
#if defined(ENABLE_CODE_CACHE)
// cache bytecode right before relocation
if (UNLIKELY(cacheByteCode)) {
context->vmInstance()->codeCache()->storeByteCodeBlock(block);
context->vmInstance()->codeCache()->storeStringTable();
}
#endif
ByteCodeGenerator::relocateByteCode(block);
#ifndef NDEBUG
ByteCodeGenerator::printByteCode(context, block);
ctx.checkAllDataUsed();
#endif
return block;
}
void ByteCodeGenerator::collectByteCodeLOCData(Context* context, InterpretedCodeBlock* codeBlock, ByteCodeLOCData* locData)
{
// this function is called only to calculate location info of each bytecode
ASSERT(!!locData && !locData->size());
GC_disable();
// Parsing
Node* ast = nullptr;
// Parsing
try {
if (codeBlock->isGlobalCodeBlock() || codeBlock->isEvalCode()) {
InterpretedCodeBlock* parentCodeBlock = codeBlock->parent();
bool allowSC = parentCodeBlock ? parentCodeBlock->allowSuperCall() : false;
bool allowSP = parentCodeBlock ? parentCodeBlock->allowSuperProperty() : false;
ast = esprima::parseProgram(context, codeBlock->src(), esprima::generateClassInfoFrom(context, codeBlock->parent()),
codeBlock->script()->isModule(), codeBlock->isStrict(), codeBlock->inWith(), allowSC, allowSP, false, true);
} else {
ast = esprima::parseSingleFunction(context, codeBlock);
}
} catch (esprima::Error* orgError) {
// ignore error
context->astAllocator().reset();
GC_enable();
return;
}
// Generate ByteCode
// ByteCodeBlock is temporally allocated on the stack
ByteCodeBlock block;
block.m_codeBlock = codeBlock;
NumeralLiteralVector* nData = nullptr;
if (ast->type() == ASTNodeType::Program) {
nData = &((ProgramNode*)ast)->numeralLiteralVector();
} else {
nData = &((FunctionNode*)ast)->numeralLiteralVector();
}
if (nData->size() == 0) {
nData = nullptr;
}
ByteCodeGenerateContext ctx(codeBlock, &block, codeBlock->isGlobalScope(), codeBlock->isEvalCode(), codeBlock->inWith(), nData);
ctx.m_locData = locData;
#ifdef ESCARGOT_DEBUGGER
// create a dummy ByteCodeBreakpointContext because we just calculate location info only
// unnecessary BreakpointLocationsInfoToDebugger insertion would incur incorrect debugger operations
ByteCodeBreakpointContext breakpointContext(context->debugger(), codeBlock, false);
ctx.m_breakpointContext = &breakpointContext;
#endif /* ESCARGOT_DEBUGGER */
try {
ast->generateStatementByteCode(&block, &ctx);
} catch (...) {
// ignore error
}
// reset ASTAllocator
context->astAllocator().reset();
GC_enable();
}
void ByteCodeGenerator::relocateByteCode(ByteCodeBlock* block)
{
InterpretedCodeBlock* codeBlock = block->codeBlock();
ByteCodeRegisterIndex stackBase = REGULAR_REGISTER_LIMIT;
ByteCodeRegisterIndex stackBaseWillBe = block->m_requiredOperandRegisterNumber;
ByteCodeRegisterIndex stackVariableSize = codeBlock->totalStackAllocatedVariableSize();
uint8_t* code = block->m_code.data();
size_t codeBase = (size_t)code;
uint8_t* end = code + block->m_code.size();
while (code < end) {
ByteCode* currentCode = (ByteCode*)code;
#if defined(ESCARGOT_COMPUTED_GOTO_INTERPRETER)
Opcode opcode = (Opcode)(size_t)currentCode->m_opcodeInAddress;
#else
Opcode opcode = currentCode->m_opcode;
#endif
currentCode->assignOpcodeInAddress();
switch (opcode) {
case LoadLiteralOpcode: {
LoadLiteral* cd = (LoadLiteral*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case LoadRegExpOpcode: {
LoadRegExp* cd = (LoadRegExp*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case LoadByNameOpcode: {
LoadByName* cd = (LoadByName*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case StoreByNameOpcode: {
StoreByName* cd = (StoreByName*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case InitializeByNameOpcode: {
InitializeByName* cd = (InitializeByName*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case StoreByNameWithAddressOpcode: {
StoreByNameWithAddress* cd = (StoreByNameWithAddress*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_valueRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case LoadByHeapIndexOpcode: {
LoadByHeapIndex* cd = (LoadByHeapIndex*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case StoreByHeapIndexOpcode: {
StoreByHeapIndex* cd = (StoreByHeapIndex*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case InitializeByHeapIndexOpcode: {
InitializeByHeapIndex* cd = (InitializeByHeapIndex*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case CreateFunctionOpcode: {
CreateFunction* cd = (CreateFunction*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_homeObjectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case CreateRestElementOpcode: {
CreateRestElement* cd = (CreateRestElement*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case CreateObjectOpcode: {
CreateObject* cd = (CreateObject*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dataRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case CreateObjectPrepareOpcode: {
CreateObjectPrepare* cd = (CreateObjectPrepare*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dataRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
if (cd->m_stage == CreateObjectPrepare::Init) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_stage == CreateObjectPrepare::FillKeyValue || cd->m_stage == CreateObjectPrepare::DefineGetterSetter) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_keyIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_valueIndex, stackBase, stackBaseWillBe, stackVariableSize);
}
break;
}
case CreateArrayOpcode: {
CreateArray* cd = (CreateArray*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case GetObjectOpcode: {
GetObject* cd = (GetObject*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_storeRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_propertyRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case SetObjectOperationOpcode: {
SetObjectOperation* cd = (SetObjectOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_propertyRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_loadRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case ObjectDefineOwnPropertyOperationOpcode: {
ObjectDefineOwnPropertyOperation* cd = (ObjectDefineOwnPropertyOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_propertyRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_loadRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case ObjectDefineOwnPropertyWithNameOperationOpcode: {
ObjectDefineOwnPropertyWithNameOperation* cd = (ObjectDefineOwnPropertyWithNameOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_loadRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_loadRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case ArrayDefineOwnPropertyOperationOpcode: {
ArrayDefineOwnPropertyOperation* cd = (ArrayDefineOwnPropertyOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
for (size_t i = 0; i < cd->m_count; i++)
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_loadRegisterIndexs[i], stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case ArrayDefineOwnPropertyBySpreadElementOperationOpcode: {
ArrayDefineOwnPropertyBySpreadElementOperation* cd = (ArrayDefineOwnPropertyBySpreadElementOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
for (size_t i = 0; i < cd->m_count; i++)
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_loadRegisterIndexs[i], stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case GetObjectPreComputedCaseOpcode: {
GetObjectPreComputedCase* cd = (GetObjectPreComputedCase*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_storeRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case SetObjectPreComputedCaseOpcode: {
SetObjectPreComputedCase* cd = (SetObjectPreComputedCase*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_loadRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case GetParameterOpcode: {
GetParameter* cd = (GetParameter*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case EndOpcode: {
End* cd = (End*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case ReturnFunctionSlowCaseOpcode: {
ReturnFunctionSlowCase* cd = (ReturnFunctionSlowCase*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case MoveOpcode: {
Move* cd = (Move*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex0, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex1, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case ObjectDefineGetterSetterOpcode: {
ObjectDefineGetterSetter* cd = (ObjectDefineGetterSetter*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectPropertyNameRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectPropertyValueRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case GetGlobalVariableOpcode: {
GetGlobalVariable* cd = (GetGlobalVariable*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case SetGlobalVariableOpcode: {
SetGlobalVariable* cd = (SetGlobalVariable*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case InitializeGlobalVariableOpcode: {
InitializeGlobalVariable* cd = (InitializeGlobalVariable*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case ToNumberOpcode:
case ToPropertyKeyOpcode:
case IncrementOpcode:
case DecrementOpcode:
case UnaryMinusOpcode:
case UnaryNotOpcode:
case UnaryBitwiseNotOpcode: {
ToNumber* cd = (ToNumber*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_srcIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dstIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case ToNumericIncrementOpcode:
case ToNumericDecrementOpcode: {
ToNumericIncrement* cd = (ToNumericIncrement*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_srcIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dstIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_storeIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case UnaryTypeofOpcode: {
UnaryTypeof* cd = (UnaryTypeof*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_srcIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dstIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case UnaryDeleteOpcode: {
UnaryDelete* cd = (UnaryDelete*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_srcIndex0, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_srcIndex1, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dstIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case TemplateOperationOpcode: {
TemplateOperation* cd = (TemplateOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_src0Index, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_src1Index, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dstIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case CallOpcode: {
Call* cd = (Call*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_calleeIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentsStartIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_resultIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case CallWithReceiverOpcode: {
CallWithReceiver* cd = (CallWithReceiver*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_receiverIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_calleeIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentsStartIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_resultIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
#if defined(ENABLE_TCO)
// TCO
case CallReturnOpcode: {
CallReturn* cd = (CallReturn*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_receiverIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_calleeIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentsStartIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case TailCallOpcode: {
TailCall* cd = (TailCall*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_receiverIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_calleeIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentsStartIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case TailRecursionOpcode: {
TailRecursion* cd = (TailRecursion*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_receiverIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_calleeIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentsStartIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case TailRecursionInTryOpcode: {
TailRecursionInTry* cd = (TailRecursionInTry*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_calleeIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentsStartIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_resultIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
#endif
case CallComplexCaseOpcode: {
CallComplexCase* cd = (CallComplexCase*)currentCode;
if (cd->m_kind != CallComplexCase::InWithScope) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_receiverOrThisIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_calleeIndex, stackBase, stackBaseWillBe, stackVariableSize);
}
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentsStartIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_resultIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case NewOperationOpcode: {
NewOperation* cd = (NewOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_calleeIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentsStartIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_resultIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case JumpOpcode: {
Jump* cd = (Jump*)currentCode;
cd->m_jumpPosition = cd->m_jumpPosition + codeBase;
break;
}
case JumpIfTrueOpcode: {
JumpIfTrue* cd = (JumpIfTrue*)currentCode;
cd->m_jumpPosition = cd->m_jumpPosition + codeBase;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case JumpIfUndefinedOrNullOpcode: {
JumpIfUndefinedOrNull* cd = (JumpIfUndefinedOrNull*)currentCode;
cd->m_jumpPosition = cd->m_jumpPosition + codeBase;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case JumpIfFalseOpcode: {
JumpIfFalse* cd = (JumpIfFalse*)currentCode;
cd->m_jumpPosition = cd->m_jumpPosition + codeBase;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case JumpIfNotFulfilledOpcode: {
JumpIfNotFulfilled* cd = (JumpIfNotFulfilled*)currentCode;
cd->m_jumpPosition = cd->m_jumpPosition + codeBase;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_leftIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_rightIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case JumpIfEqualOpcode: {
JumpIfEqual* cd = (JumpIfEqual*)currentCode;
cd->m_jumpPosition = cd->m_jumpPosition + codeBase;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex0, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex1, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case ThrowOperationOpcode: {
ThrowOperation* cd = (ThrowOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case CreateEnumerateObjectOpcode: {
CreateEnumerateObject* cd = (CreateEnumerateObject*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case IteratorOperationOpcode: {
IteratorOperation* cd = (IteratorOperation*)currentCode;
if (cd->m_operation == IteratorOperation::Operation::GetIterator) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_getIteratorData.m_srcObjectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_getIteratorData.m_dstIteratorRecordIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_getIteratorData.m_dstIteratorObjectIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_operation == IteratorOperation::Operation::IteratorClose) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_iteratorCloseData.m_iterRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_iteratorCloseData.m_execeptionRegisterIndexIfExists, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_operation == IteratorOperation::Operation::IteratorBind) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_iteratorBindData.m_iterRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_operation == IteratorOperation::Operation::IteratorTestDone) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_iteratorTestDoneData.m_dstRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_operation == IteratorOperation::Operation::IteratorNext) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_iteratorNextData.m_iteratorRecordRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_iteratorNextData.m_valueRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_iteratorNextData.m_valueRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_operation == IteratorOperation::Operation::IteratorTestResultIsObject) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_iteratorTestResultIsObjectData.m_valueRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_operation == IteratorOperation::Operation::IteratorValue) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_iteratorValueData.m_srcRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_iteratorValueData.m_dstRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_operation == IteratorOperation::Operation::IteratorCheckOngoingExceptionOnAsyncIteratorClose) {
} else {
ASSERT_NOT_REACHED();
}
break;
}
case GetMethodOpcode: {
GetMethod* cd = (GetMethod*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_resultRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case BindingRestElementOpcode: {
BindingRestElement* cd = (BindingRestElement*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_iterOrEnumIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dstIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case OpenLexicalEnvironmentOpcode: {
OpenLexicalEnvironment* cd = (OpenLexicalEnvironment*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_withOrThisRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case BinaryPlusOpcode:
case BinaryMinusOpcode:
case BinaryMultiplyOpcode:
case BinaryDivisionOpcode:
case BinaryModOpcode:
case BinaryEqualOpcode:
case BinaryLessThanOpcode:
case BinaryLessThanOrEqualOpcode:
case BinaryGreaterThanOpcode:
case BinaryGreaterThanOrEqualOpcode:
case BinaryStrictEqualOpcode:
case BinaryBitwiseAndOpcode:
case BinaryBitwiseOrOpcode:
case BinaryBitwiseXorOpcode:
case BinaryLeftShiftOpcode:
case BinarySignedRightShiftOpcode:
case BinaryUnsignedRightShiftOpcode:
case BinaryInOperationOpcode:
case BinaryInstanceOfOperationOpcode:
case BinaryExponentiationOpcode: {
BinaryPlus* plus = (BinaryPlus*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(plus->m_srcIndex0, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(plus->m_srcIndex1, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(plus->m_dstIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case CreateSpreadArrayObjectOpcode: {
CreateSpreadArrayObject* cd = (CreateSpreadArrayObject*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case NewOperationWithSpreadElementOpcode: {
NewOperationWithSpreadElement* cd = (NewOperationWithSpreadElement*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_calleeIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentsStartIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_resultIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case InitializeClassOpcode: {
InitializeClass* cd = (InitializeClass*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_classConstructorRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
if (cd->m_stage == InitializeClass::CreateClass) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_classPrototypeRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_superClassRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_stage == InitializeClass::InitField) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_propertyInitRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_stage == InitializeClass::SetFieldData) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_propertySetRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_stage == InitializeClass::InitStaticField) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_staticPropertyInitRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else if (cd->m_stage == InitializeClass::SetStaticFieldData) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_staticPropertySetRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
}
break;
}
case SuperReferenceOpcode: {
SuperReference* cd = (SuperReference*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dstIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case ComplexSetObjectOperationOpcode: {
ComplexSetObjectOperation* cd = (ComplexSetObjectOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_loadRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
if (cd->m_type == ComplexSetObjectOperation::Super) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_propertyNameIndex, stackBase, stackBaseWillBe, stackVariableSize);
}
break;
}
case ComplexGetObjectOperationOpcode: {
ComplexGetObjectOperation* cd = (ComplexGetObjectOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_objectRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_storeRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
if (cd->m_type == ComplexGetObjectOperation::Super) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_propertyNameIndex, stackBase, stackBaseWillBe, stackVariableSize);
}
break;
}
case LoadThisBindingOpcode: {
LoadThisBinding* cd = (LoadThisBinding*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dstIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case ExecutionPauseOpcode: {
ExecutionPause* cd = (ExecutionPause*)currentCode;
if (cd->m_reason == ExecutionPause::Reason::Yield) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_yieldData.m_yieldIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_yieldData.m_dstIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_yieldData.m_dstStateIndex, stackBase, stackBaseWillBe, stackVariableSize);
code += cd->m_yieldData.m_tailDataLength;
} else if (cd->m_reason == ExecutionPause::Reason::Await) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_awaitData.m_awaitIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_awaitData.m_dstIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_awaitData.m_dstStateIndex, stackBase, stackBaseWillBe, stackVariableSize);
code += cd->m_awaitData.m_tailDataLength;
} else if (cd->m_reason == ExecutionPause::Reason::GeneratorsInitialize) {
code += cd->m_asyncGeneratorInitializeData.m_tailDataLength;
}
break;
}
case TryOperationOpcode: {
TryOperation* cd = (TryOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_catchedValueRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case MetaPropertyOperationOpcode: {
MetaPropertyOperation* cd = (MetaPropertyOperation*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case TaggedTemplateOperationOpcode: {
TaggedTemplateOperation* cd = (TaggedTemplateOperation*)currentCode;
if (cd->m_operaton == TaggedTemplateOperation::TestCacheOperation) {
cd->m_testCacheOperationData.m_jumpPosition = cd->m_testCacheOperationData.m_jumpPosition + codeBase;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_testCacheOperationData.m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
} else {
ASSERT(cd->m_operaton == TaggedTemplateOperation::FillCacheOperation);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_fillCacheOperationData.m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
}
break;
}
case InitializeDisposableOpcode: {
InitializeDisposable* cd = (InitializeDisposable*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_srcRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dstRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case FinalizeDisposableOpcode: {
FinalizeDisposable* cd = (FinalizeDisposable*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dataRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
code += cd->m_tailDataLength;
break;
}
default:
break;
}
#ifdef ESCARGOT_DEBUGGER
ASSERT((opcode <= EndOpcode) || (opcode == BreakpointDisabledOpcode || opcode == BreakpointEnabledOpcode));
#else
ASSERT(opcode <= EndOpcode);
#endif
code += byteCodeLengths[opcode];
}
}
#ifndef NDEBUG
void ByteCodeGenerator::printByteCode(Context* context, ByteCodeBlock* block)
{
ASSERT(!!block->codeBlock());
InterpretedCodeBlock* codeBlock = block->codeBlock();
char* dumpByteCode = getenv("DUMP_BYTECODE");
if (dumpByteCode && (strcmp(dumpByteCode, "1") == 0)) {
printf("dumpBytecode %s (%d:%d)>>>>>>>>>>>>>>>>>>>>>>\n", codeBlock->functionName().string()->toUTF8StringData().data(), (int)codeBlock->functionStart().line, (int)codeBlock->functionStart().column);
printf("register info.. (stack variable total(%d), this + function + var (%d), max lexical depth (%d)) [", (int)codeBlock->totalStackAllocatedVariableSize(), (int)codeBlock->identifierOnStackCount(), (int)codeBlock->lexicalBlockStackAllocatedIdentifierMaximumDepth());
for (size_t i = 0; i < block->m_requiredOperandRegisterNumber; i++) {
printf("r%d,", (int)i);
}
size_t b = block->m_requiredOperandRegisterNumber + 1;
printf("`r%d this`,", (int)block->m_requiredOperandRegisterNumber);
if (!codeBlock->isGlobalCodeBlock()) {
printf("`r%d function`,", (int)b);
b++;
}
size_t localStart = 0;
if (codeBlock->isFunctionNameSaveOnHeap() || codeBlock->isFunctionNameUsedBySelf()) {
localStart = 1;
}
for (size_t i = localStart; i < codeBlock->identifierInfos().size(); i++) {
if (codeBlock->identifierInfos()[i].m_needToAllocateOnStack) {
auto name = codeBlock->identifierInfos()[i].m_name.string()->toNonGCUTF8StringData();
printf("`r%d,var %s`,", (int)b++, name.data());
}
}
size_t lexIndex = 0;
for (size_t i = 0; i < codeBlock->lexicalBlockStackAllocatedIdentifierMaximumDepth(); i++) {
printf("`r%d,%d lexical`,", (int)b++, (int)lexIndex++);
}
ExecutionState tempState(context);
for (size_t i = 0; i < block->m_numeralLiteralData.size(); i++) {
printf("`r%d,%s(literal)`,", (int)b++, block->m_numeralLiteralData[i].toString(tempState)->toUTF8StringData().data());
}
printf("]\n");
ByteCode::dumpCode(block->m_code.data(), block->m_code.size());
printf("dumpBytecode...<<<<<<<<<<<<<<<<<<<<<<\n");
}
}
#endif
} // namespace Escargot