escargot/src/interpreter/ByteCodeGenerator.h
HyukWoo Park 11e469c6fa Implement CodeCache for bytecode
* store/load global ByteCodeBlock

Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
2020-08-03 10:40:17 +09:00

413 lines
17 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
*/
#ifndef __EscargotByteCodeGenerator__
#define __EscargotByteCodeGenerator__
#include "parser/ast/Node.h"
#include "debugger/Debugger.h"
namespace Escargot {
extern const uint8_t byteCodeLengths[];
class Context;
class CodeBlock;
class ByteCodeBlock;
class Node;
class InterpretedCodeBlock;
struct ClassContextInformation {
ClassContextInformation()
: m_constructorIndex(SIZE_MAX)
, m_prototypeIndex(SIZE_MAX)
, m_superIndex(SIZE_MAX)
, m_name(AtomicString())
, m_src(String::emptyString)
{
}
size_t m_constructorIndex;
size_t m_prototypeIndex;
size_t m_superIndex;
AtomicString m_name;
String* m_src;
};
struct ParserContextInformation {
ParserContextInformation(bool isEvalCode = false, bool isForGlobalScope = false, bool isStrict = false, bool isWithScope = false)
: m_isEvalCode(isEvalCode)
, m_isForGlobalScope(isForGlobalScope)
, m_isWithScope(isWithScope)
{
// NOTE: ES5 10.4.2.1
if (isEvalCode && isStrict)
m_isForGlobalScope = false;
}
bool m_isEvalCode : 1;
bool m_isForGlobalScope : 1;
bool m_isWithScope : 1;
};
#ifdef ESCARGOT_DEBUGGER
struct ByteCodeBreakpointContext {
size_t m_lastBreakpointLineOffset;
size_t m_lastBreakpointIndexOffset;
std::vector<Debugger::BreakpointLocation> m_breakpointLocations;
ByteCodeBreakpointContext()
: m_lastBreakpointLineOffset(0)
, m_lastBreakpointIndexOffset(0)
{
}
};
#endif /* ESCARGOT_DEBUGGER */
struct ByteCodeGenerateContext {
ByteCodeGenerateContext(InterpretedCodeBlock* codeBlock, ByteCodeBlock* byteCodeBlock, ParserContextInformation& parserContextInformation, NumeralLiteralVector* numeralLiteralData)
: m_baseRegisterCount(0)
, m_codeBlock(codeBlock)
, m_byteCodeBlock(byteCodeBlock)
, m_isGlobalScope(parserContextInformation.m_isForGlobalScope)
, m_isEvalCode(parserContextInformation.m_isEvalCode)
, m_isOutermostContext(true)
, m_isWithScope(parserContextInformation.m_isWithScope)
, m_isFunctionDeclarationBindingInitialization(false)
, m_isVarDeclaredBindingInitialization(false)
, m_isLexicallyDeclaredBindingInitialization(false)
, m_canSkipCopyToRegister(true)
, m_keepNumberalLiteralsInRegisterFile(numeralLiteralData)
, m_inObjectDestruction(false)
, m_inParameterInitialization(false)
, m_shouldGenerateLOCData(false)
, m_forInOfVarBinding(false)
, m_isLeftBindingAffectedByRightExpression(false)
, m_registerStack(new std::vector<ByteCodeRegisterIndex>())
, m_lexicallyDeclaredNames(new std::vector<std::pair<size_t, AtomicString>>())
, m_positionToContinue(0)
, m_complexJumpBreakIgnoreCount(0)
, m_complexJumpContinueIgnoreCount(0)
, m_complexJumpLabeledBreakIgnoreCount(0)
, m_complexJumpLabeledContinueIgnoreCount(0)
, m_lexicalBlockIndex(0)
, m_maxPauseStatementExtraDataLength(0)
, m_numeralLiteralData(numeralLiteralData)
#ifdef ESCARGOT_DEBUGGER
, m_breakpointContext(nullptr)
#endif /* ESCARGOT_DEBUGGER */
{
m_inCallingExpressionScope = false;
m_isHeadOfMemberExpression = false;
m_classInfo = ClassContextInformation();
}
ByteCodeGenerateContext(const ByteCodeGenerateContext& contextBefore)
: m_baseRegisterCount(contextBefore.m_baseRegisterCount)
, m_codeBlock(contextBefore.m_codeBlock)
, m_byteCodeBlock(contextBefore.m_byteCodeBlock)
, m_isGlobalScope(contextBefore.m_isGlobalScope)
, m_isEvalCode(contextBefore.m_isEvalCode)
, m_isOutermostContext(false)
, m_isWithScope(contextBefore.m_isWithScope)
, m_isFunctionDeclarationBindingInitialization(contextBefore.m_isFunctionDeclarationBindingInitialization)
, m_isVarDeclaredBindingInitialization(contextBefore.m_isVarDeclaredBindingInitialization)
, m_isLexicallyDeclaredBindingInitialization(contextBefore.m_isLexicallyDeclaredBindingInitialization)
, m_canSkipCopyToRegister(contextBefore.m_canSkipCopyToRegister)
, m_keepNumberalLiteralsInRegisterFile(contextBefore.m_keepNumberalLiteralsInRegisterFile)
, m_inCallingExpressionScope(contextBefore.m_inCallingExpressionScope)
, m_inObjectDestruction(contextBefore.m_inObjectDestruction)
, m_inParameterInitialization(contextBefore.m_inParameterInitialization)
, m_shouldGenerateLOCData(contextBefore.m_shouldGenerateLOCData)
, m_forInOfVarBinding(contextBefore.m_forInOfVarBinding)
, m_isLeftBindingAffectedByRightExpression(contextBefore.m_isLeftBindingAffectedByRightExpression)
, m_registerStack(contextBefore.m_registerStack)
, m_lexicallyDeclaredNames(contextBefore.m_lexicallyDeclaredNames)
, m_positionToContinue(contextBefore.m_positionToContinue)
, m_recursiveStatementStack(contextBefore.m_recursiveStatementStack)
, m_complexJumpBreakIgnoreCount(contextBefore.m_complexJumpBreakIgnoreCount)
, m_complexJumpContinueIgnoreCount(contextBefore.m_complexJumpContinueIgnoreCount)
, m_complexJumpLabeledBreakIgnoreCount(contextBefore.m_complexJumpLabeledBreakIgnoreCount)
, m_complexJumpLabeledContinueIgnoreCount(contextBefore.m_complexJumpLabeledContinueIgnoreCount)
, m_lexicalBlockIndex(contextBefore.m_lexicalBlockIndex)
, m_classInfo(contextBefore.m_classInfo)
, m_maxPauseStatementExtraDataLength(contextBefore.m_maxPauseStatementExtraDataLength)
, m_numeralLiteralData(contextBefore.m_numeralLiteralData)
#ifdef ESCARGOT_DEBUGGER
, m_breakpointContext(contextBefore.m_breakpointContext)
#endif /* ESCARGOT_DEBUGGER */
{
m_isHeadOfMemberExpression = false;
}
~ByteCodeGenerateContext()
{
}
void propagateInformationTo(ByteCodeGenerateContext& ctx)
{
ctx.m_breakStatementPositions.insert(ctx.m_breakStatementPositions.end(), m_breakStatementPositions.begin(), m_breakStatementPositions.end());
ctx.m_continueStatementPositions.insert(ctx.m_continueStatementPositions.end(), m_continueStatementPositions.begin(), m_continueStatementPositions.end());
ctx.m_labeledBreakStatmentPositions.insert(ctx.m_labeledBreakStatmentPositions.end(), m_labeledBreakStatmentPositions.begin(), m_labeledBreakStatmentPositions.end());
ctx.m_labeledContinueStatmentPositions.insert(ctx.m_labeledContinueStatmentPositions.end(), m_labeledContinueStatmentPositions.begin(), m_labeledContinueStatmentPositions.end());
ctx.m_complexCaseStatementPositions.insert(m_complexCaseStatementPositions.begin(), m_complexCaseStatementPositions.end());
ctx.m_positionToContinue = m_positionToContinue;
ctx.m_lexicalBlockIndex = m_lexicalBlockIndex;
ctx.m_classInfo = m_classInfo;
ctx.m_maxPauseStatementExtraDataLength = std::max(m_maxPauseStatementExtraDataLength, ctx.m_maxPauseStatementExtraDataLength);
m_breakStatementPositions.clear();
m_continueStatementPositions.clear();
m_labeledBreakStatmentPositions.clear();
m_labeledContinueStatmentPositions.clear();
m_complexCaseStatementPositions.clear();
ctx.m_recursiveStatementStack = std::move(m_recursiveStatementStack);
}
void pushBreakPositions(size_t pos)
{
m_breakStatementPositions.push_back(pos);
}
void pushLabeledBreakPositions(size_t pos, String* lbl)
{
m_labeledBreakStatmentPositions.push_back(std::make_pair(lbl, pos));
}
void pushContinuePositions(size_t pos)
{
m_continueStatementPositions.push_back(pos);
}
void pushLabeledContinuePositions(size_t pos, String* lbl)
{
m_labeledContinueStatmentPositions.push_back(std::make_pair(lbl, pos));
}
void registerJumpPositionsToComplexCase(size_t frontlimit)
{
ASSERT(tryCatchWithBlockStatementCount());
for (unsigned i = 0; i < m_breakStatementPositions.size(); i++) {
if (m_breakStatementPositions[i] > (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_breakStatementPositions[i]) == m_complexCaseStatementPositions.end()) {
if (tryCatchWithBlockStatementCount() - m_complexJumpBreakIgnoreCount > 0) {
m_complexCaseStatementPositions.insert(std::make_pair(m_breakStatementPositions[i], tryCatchWithBlockStatementCount() - m_complexJumpBreakIgnoreCount));
}
}
}
for (unsigned i = 0; i < m_continueStatementPositions.size(); i++) {
if (m_continueStatementPositions[i] > (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_continueStatementPositions[i]) == m_complexCaseStatementPositions.end()) {
if (tryCatchWithBlockStatementCount() - m_complexJumpContinueIgnoreCount > 0) {
m_complexCaseStatementPositions.insert(std::make_pair(m_continueStatementPositions[i], tryCatchWithBlockStatementCount() - m_complexJumpContinueIgnoreCount));
}
}
}
for (unsigned i = 0; i < m_labeledBreakStatmentPositions.size(); i++) {
if (m_labeledBreakStatmentPositions[i].second > (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_labeledBreakStatmentPositions[i].second) == m_complexCaseStatementPositions.end()) {
if (tryCatchWithBlockStatementCount() - m_complexJumpLabeledBreakIgnoreCount > 0) {
m_complexCaseStatementPositions.insert(std::make_pair(m_labeledBreakStatmentPositions[i].second, tryCatchWithBlockStatementCount() - m_complexJumpLabeledBreakIgnoreCount));
}
}
}
for (unsigned i = 0; i < m_labeledContinueStatmentPositions.size(); i++) {
if (m_labeledContinueStatmentPositions[i].second > (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_labeledContinueStatmentPositions[i].second) == m_complexCaseStatementPositions.end()) {
if (tryCatchWithBlockStatementCount() - m_complexJumpLabeledContinueIgnoreCount > 0) {
m_complexCaseStatementPositions.insert(std::make_pair(m_labeledContinueStatmentPositions[i].second, tryCatchWithBlockStatementCount() - m_complexJumpLabeledContinueIgnoreCount));
}
}
}
}
size_t getLastRegisterIndex()
{
return m_registerStack->back();
}
size_t getLastRegisterIndex(size_t idx)
{
return *(m_registerStack->end() - idx - 1);
}
size_t getRegister()
{
if ((m_baseRegisterCount + 1) > REGULAR_REGISTER_LIMIT) {
throw "register limit exceed";
}
RELEASE_ASSERT(m_baseRegisterCount + 1 < REGULAR_REGISTER_LIMIT);
m_registerStack->push_back(m_baseRegisterCount);
m_baseRegisterCount++;
return m_registerStack->back();
}
void pushRegister(ByteCodeRegisterIndex index)
{
if (index == m_baseRegisterCount) {
m_baseRegisterCount++;
}
m_registerStack->push_back(index);
}
void giveUpRegister()
{
ASSERT(m_registerStack->size());
if (m_registerStack->back() == (m_baseRegisterCount - 1)) {
m_baseRegisterCount--;
}
m_registerStack->pop_back();
}
void consumeBreakPositions(ByteCodeBlock* cb, size_t position, int outerLimitCount);
void consumeLabeledBreakPositions(ByteCodeBlock* cb, size_t position, String* lbl, int outerLimitCount);
void consumeContinuePositions(ByteCodeBlock* cb, size_t position, int outerLimitCount);
void consumeLabeledContinuePositions(ByteCodeBlock* cb, size_t position, String* lbl, int outerLimitCount);
void morphJumpPositionIntoComplexCase(ByteCodeBlock* cb, size_t codePos, size_t outerLimitCount = SIZE_MAX);
bool isGlobalScope()
{
return m_isGlobalScope;
}
bool shouldCareScriptExecutionResult()
{
return (m_isGlobalScope | m_isEvalCode) && m_baseRegisterCount == 0;
}
void addLexicallyDeclaredNames(AtomicString name)
{
bool find = false;
auto iter = m_lexicallyDeclaredNames->begin();
while (iter != m_lexicallyDeclaredNames->end()) {
if (iter->first == m_lexicalBlockIndex && iter->second == name) {
find = true;
break;
}
iter++;
}
if (!find) {
m_lexicallyDeclaredNames->push_back(std::make_pair(m_lexicalBlockIndex, name));
}
}
void addInitializedParameterNames(AtomicString name)
{
bool find = false;
for (size_t i = 0; i < m_initializedParameterNames.size(); i++) {
if (m_initializedParameterNames[i] == name) {
find = true;
break;
}
}
if (!find) {
m_initializedParameterNames.push_back(name);
}
}
int tryCatchWithBlockStatementCount()
{
return m_recursiveStatementStack.size();
}
bool inTryStatement()
{
for (size_t i = 0; i < m_recursiveStatementStack.size(); i++) {
if (m_recursiveStatementStack[i].first == Try) {
return true;
}
}
return false;
}
#ifdef ESCARGOT_DEBUGGER
size_t calculateBreakpointLineOffset(size_t index, ExtendedNodeLOC sourceElementStart);
void insertBreakpoint(size_t index, Node* node);
void insertBreakpointAt(size_t line, Node* node);
#endif /* ESCARGOT_DEBUGGER */
// NOTE this is counter! not index!!!!!!
size_t m_baseRegisterCount;
InterpretedCodeBlock* m_codeBlock;
ByteCodeBlock* m_byteCodeBlock;
bool m_isGlobalScope : 1;
bool m_isEvalCode : 1;
bool m_isOutermostContext : 1;
bool m_isWithScope : 1;
bool m_isFunctionDeclarationBindingInitialization : 1;
bool m_isVarDeclaredBindingInitialization : 1;
bool m_isLexicallyDeclaredBindingInitialization : 1;
bool m_canSkipCopyToRegister : 1;
bool m_keepNumberalLiteralsInRegisterFile : 1;
bool m_inCallingExpressionScope : 1;
bool m_inObjectDestruction : 1;
bool m_inParameterInitialization : 1;
bool m_isHeadOfMemberExpression : 1;
bool m_shouldGenerateLOCData : 1;
bool m_forInOfVarBinding : 1;
bool m_isLeftBindingAffectedByRightExpression : 1; // x = delete x; or x = eval("var x"), 1;
std::shared_ptr<std::vector<ByteCodeRegisterIndex>> m_registerStack;
std::shared_ptr<std::vector<std::pair<size_t, AtomicString>>> m_lexicallyDeclaredNames;
std::vector<AtomicString> m_initializedParameterNames;
std::vector<size_t> m_breakStatementPositions;
std::vector<size_t> m_continueStatementPositions;
std::vector<std::pair<String*, size_t>> m_labeledBreakStatmentPositions;
std::vector<std::pair<String*, size_t>> m_labeledContinueStatmentPositions;
std::vector<size_t> m_getObjectCodePositions;
// For Label Statement
size_t m_positionToContinue;
// code position, special Statement count
enum RecursiveStatementKind : size_t {
Try,
Catch,
Finally,
With,
Block
};
std::vector<std::pair<RecursiveStatementKind, size_t>> m_recursiveStatementStack;
int m_complexJumpBreakIgnoreCount;
int m_complexJumpContinueIgnoreCount;
int m_complexJumpLabeledBreakIgnoreCount;
int m_complexJumpLabeledContinueIgnoreCount;
size_t m_lexicalBlockIndex;
ClassContextInformation m_classInfo;
std::map<size_t, size_t> m_complexCaseStatementPositions;
size_t m_maxPauseStatementExtraDataLength;
NumeralLiteralVector* m_numeralLiteralData;
#ifdef ESCARGOT_DEBUGGER
ByteCodeBreakpointContext* m_breakpointContext;
#endif /* ESCARGOT_DEBUGGER */
};
class ByteCodeGenerator {
public:
static ByteCodeBlock* generateByteCode(Context* context, InterpretedCodeBlock* codeBlock, Node* ast, bool isEvalMode = false, bool isOnGlobal = false, bool inWithFromRuntime = false, bool shouldGenerateLOCData = false, bool cacheByteCode = false);
static void relocateByteCode(ByteCodeBlock* block);
#ifndef NDEBUG
static void printByteCode(Context* context, ByteCodeBlock* block);
#endif
};
}
#endif