mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
262 lines
9.9 KiB
C++
262 lines
9.9 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 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 "ByteCode.h"
|
|
#include "ByteCodeInterpreter.h"
|
|
#include "runtime/Context.h"
|
|
#include "parser/Lexer.h"
|
|
#include "parser/ScriptParser.h"
|
|
#include "parser/ast/AST.h"
|
|
#include "parser/esprima_cpp/esprima.h"
|
|
|
|
namespace Escargot {
|
|
|
|
OpcodeTable g_opcodeTable;
|
|
|
|
OpcodeTable::OpcodeTable()
|
|
{
|
|
#if defined(COMPILER_GCC)
|
|
// Dummy bytecode execution to initialize the OpcodeTable.
|
|
ByteCodeInterpreter::interpret(nullptr, nullptr, 0, nullptr);
|
|
#endif
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
void ByteCode::dumpCode(size_t pos, const char* byteCodeStart)
|
|
{
|
|
printf("%d\t\t", (int)pos);
|
|
|
|
const char* opcodeName = NULL;
|
|
switch (m_orgOpcode) {
|
|
#define RETURN_BYTECODE_NAME(name, pushCount, popCount) \
|
|
case name##Opcode: \
|
|
((name*)this)->dump(byteCodeStart); \
|
|
opcodeName = #name; \
|
|
break;
|
|
FOR_EACH_BYTECODE_OP(RETURN_BYTECODE_NAME)
|
|
#undef RETURN_BYTECODE_NAME
|
|
default:
|
|
RELEASE_ASSERT_NOT_REACHED();
|
|
}
|
|
|
|
printf(" | %s ", opcodeName);
|
|
printf("(line: %d:%d)\n", (int)m_loc.line, (int)m_loc.column);
|
|
}
|
|
|
|
int ByteCode::dumpJumpPosition(size_t pos, const char* byteCodeStart)
|
|
{
|
|
return (int)(pos - (size_t)byteCodeStart);
|
|
}
|
|
|
|
void GetGlobalVariable::dump(const char* byteCodeStart)
|
|
{
|
|
printf("get global variable r%d <- global.%s", (int)m_registerIndex, m_slot->m_propertyName.string()->toUTF8StringData().data());
|
|
}
|
|
|
|
void SetGlobalVariable::dump(const char* byteCodeStart)
|
|
{
|
|
printf("set global variable global.%s <- r%d", m_slot->m_propertyName.string()->toUTF8StringData().data(), (int)m_registerIndex);
|
|
}
|
|
#endif
|
|
|
|
void* ByteCodeBlock::operator new(size_t size)
|
|
{
|
|
static bool typeInited = false;
|
|
static GC_descr descr;
|
|
if (!typeInited) {
|
|
GC_word obj_bitmap[GC_BITMAP_SIZE(ByteCodeBlock)] = { 0 };
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ByteCodeBlock, m_literalData));
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ByteCodeBlock, m_codeBlock));
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ByteCodeBlock, m_objectStructuresInUse));
|
|
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(ByteCodeBlock));
|
|
typeInited = true;
|
|
}
|
|
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
|
|
}
|
|
|
|
void ByteCodeBlock::fillLocDataIfNeeded(Context* c)
|
|
{
|
|
if (!m_codeBlock->isInterpretedCodeBlock() || m_locData || (m_codeBlock->isInterpretedCodeBlock() && m_codeBlock->asInterpretedCodeBlock()->src().length() == 0)) {
|
|
return;
|
|
}
|
|
|
|
GC_disable();
|
|
|
|
ByteCodeBlock* block;
|
|
// TODO give correct stack limit to parser
|
|
if (m_codeBlock->asInterpretedCodeBlock()->isGlobalScopeCodeBlock()) {
|
|
ProgramNode* nd = esprima::parseProgram(c, m_codeBlock->asInterpretedCodeBlock()->src(), m_codeBlock->script()->isModule(), m_codeBlock->asInterpretedCodeBlock()->isStrict(), m_codeBlock->inWith(), SIZE_MAX, false, false, false);
|
|
block = ByteCodeGenerator::generateByteCode(c, m_codeBlock->asInterpretedCodeBlock(), nd, nd->scopeContext(), m_isEvalMode, m_isOnGlobal, false, true);
|
|
} else {
|
|
ASTFunctionScopeContext* scopeContext = nullptr;
|
|
auto body = esprima::parseSingleFunction(c, m_codeBlock->asInterpretedCodeBlock(), scopeContext, SIZE_MAX);
|
|
block = ByteCodeGenerator::generateByteCode(c, m_codeBlock->asInterpretedCodeBlock(), body, scopeContext, m_isEvalMode, m_isOnGlobal, false, true);
|
|
}
|
|
m_locData = block->m_locData;
|
|
block->m_locData = nullptr;
|
|
// prevent infinate fillLocDataIfNeeded if m_locData.size() == 0 in here
|
|
m_locData->push_back(std::make_pair(SIZE_MAX, SIZE_MAX));
|
|
|
|
// reset ASTAllocator
|
|
c->astAllocator().reset();
|
|
GC_enable();
|
|
}
|
|
|
|
ExtendedNodeLOC ByteCodeBlock::computeNodeLOCFromByteCode(Context* c, size_t codePosition, CodeBlock* cb)
|
|
{
|
|
if (codePosition == SIZE_MAX) {
|
|
return ExtendedNodeLOC(SIZE_MAX, SIZE_MAX, SIZE_MAX);
|
|
}
|
|
|
|
fillLocDataIfNeeded(c);
|
|
|
|
size_t index = 0;
|
|
for (size_t i = 0; i < m_locData->size(); i++) {
|
|
if ((*m_locData)[i].first == codePosition) {
|
|
index = (*m_locData)[i].second;
|
|
if (index == SIZE_MAX) {
|
|
return ExtendedNodeLOC(SIZE_MAX, SIZE_MAX, SIZE_MAX);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
size_t indexRelatedWithScript = index;
|
|
index -= cb->asInterpretedCodeBlock()->sourceElementStart().index;
|
|
|
|
auto result = computeNodeLOC(cb->asInterpretedCodeBlock()->src(), cb->asInterpretedCodeBlock()->sourceElementStart(), index);
|
|
result.index = indexRelatedWithScript;
|
|
|
|
return result;
|
|
}
|
|
|
|
ExtendedNodeLOC ByteCodeBlock::computeNodeLOC(StringView src, ExtendedNodeLOC sourceElementStart, size_t index)
|
|
{
|
|
size_t line = sourceElementStart.line;
|
|
size_t column = sourceElementStart.column;
|
|
size_t srcLength = src.length();
|
|
for (size_t i = 0; i < index && i < srcLength; i++) {
|
|
char16_t c = src.charAt(i);
|
|
column++;
|
|
if (EscargotLexer::isLineTerminator(c)) {
|
|
// skip \r\n
|
|
if (c == 13 && (i + 1 < index) && src.charAt(i + 1) == 10) {
|
|
i++;
|
|
}
|
|
line++;
|
|
column = 1;
|
|
}
|
|
}
|
|
return ExtendedNodeLOC(line, column, index);
|
|
}
|
|
|
|
void ByteCodeBlock::initFunctionDeclarationWithinBlock(ByteCodeGenerateContext* context, InterpretedCodeBlock::BlockInfo* bi, Node* node)
|
|
{
|
|
InterpretedCodeBlock* codeBlock = context->m_codeBlock->asInterpretedCodeBlock();
|
|
|
|
InterpretedCodeBlock* child = codeBlock->firstChild();
|
|
while (child) {
|
|
if (child->isFunctionDeclaration() && child->asInterpretedCodeBlock()->lexicalBlockIndexFunctionLocatedIn() == context->m_lexicalBlockIndex) {
|
|
IdentifierNode* id = new (alloca(sizeof(IdentifierNode))) IdentifierNode(child->functionName());
|
|
id->m_loc = node->m_loc;
|
|
|
|
// add useless register for don't ruin script result
|
|
// because script or eval result is final value of first register
|
|
// eg) function foo() {} -> result should be `undefined` not `function foo`
|
|
context->getRegister();
|
|
|
|
auto dstIndex = id->getRegister(this, context);
|
|
pushCode(CreateFunction(ByteCodeLOC(node->m_loc.index), dstIndex, SIZE_MAX, child), context, node);
|
|
context->m_isFunctionDeclarationBindingInitialization = true;
|
|
id->generateStoreByteCode(this, context, dstIndex, true);
|
|
context->giveUpRegister();
|
|
|
|
context->giveUpRegister(); // give up useless register
|
|
}
|
|
|
|
child = child->nextSibling();
|
|
}
|
|
}
|
|
|
|
ByteCodeBlock::ByteCodeLexicalBlockContext ByteCodeBlock::pushLexicalBlock(ByteCodeGenerateContext* context, InterpretedCodeBlock::BlockInfo* bi, Node* node)
|
|
{
|
|
ByteCodeBlock::ByteCodeLexicalBlockContext ctx;
|
|
InterpretedCodeBlock* codeBlock = context->m_codeBlock->asInterpretedCodeBlock();
|
|
|
|
ctx.lexicallyDeclaredNamesCount = context->m_lexicallyDeclaredNames->size();
|
|
|
|
if (bi->m_shouldAllocateEnvironment) {
|
|
ctx.lexicalBlockSetupStartPosition = currentCodeSize();
|
|
context->m_recursiveStatementStack.push_back(std::make_pair(ByteCodeGenerateContext::Block, ctx.lexicalBlockSetupStartPosition));
|
|
this->pushCode(BlockOperation(ByteCodeLOC(node->m_loc.index), bi), context, nullptr);
|
|
}
|
|
|
|
initFunctionDeclarationWithinBlock(context, bi, node);
|
|
ctx.lexicalBlockStartPosition = currentCodeSize();
|
|
|
|
return ctx;
|
|
}
|
|
|
|
void ByteCodeBlock::finalizeLexicalBlock(ByteCodeGenerateContext* context, const ByteCodeBlock::ByteCodeLexicalBlockContext& ctx)
|
|
{
|
|
context->m_lexicallyDeclaredNames->resize(ctx.lexicallyDeclaredNamesCount);
|
|
|
|
if (ctx.lexicalBlockSetupStartPosition == SIZE_MAX) {
|
|
return;
|
|
}
|
|
|
|
if (ctx.lexicalBlockStartPosition != SIZE_MAX) {
|
|
context->registerJumpPositionsToComplexCase(ctx.lexicalBlockStartPosition);
|
|
}
|
|
|
|
this->pushCode(TryCatchFinallyWithBlockBodyEnd(ByteCodeLOC(SIZE_MAX)), context, nullptr);
|
|
this->peekCode<BlockOperation>(ctx.lexicalBlockSetupStartPosition)->m_blockEndPosition = this->currentCodeSize();
|
|
context->m_recursiveStatementStack.pop_back();
|
|
}
|
|
|
|
void* SetObjectInlineCache::operator new(size_t size)
|
|
{
|
|
static bool typeInited = false;
|
|
static GC_descr descr;
|
|
if (!typeInited) {
|
|
GC_word obj_bitmap[GC_BITMAP_SIZE(SetObjectInlineCache)] = { 0 };
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(SetObjectInlineCache, m_cachedhiddenClassChain));
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(SetObjectInlineCache, m_hiddenClassWillBe));
|
|
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(SetObjectInlineCache));
|
|
typeInited = true;
|
|
}
|
|
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
|
|
}
|
|
|
|
void* EnumerateObjectData::operator new(size_t size)
|
|
{
|
|
static bool typeInited = false;
|
|
static GC_descr descr;
|
|
if (!typeInited) {
|
|
GC_word obj_bitmap[GC_BITMAP_SIZE(EnumerateObjectData)] = { 0 };
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(EnumerateObjectData, m_hiddenClassChain));
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(EnumerateObjectData, m_object));
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(EnumerateObjectData, m_keys));
|
|
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(EnumerateObjectData));
|
|
typeInited = true;
|
|
}
|
|
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
|
|
}
|
|
}
|