escargot/src/interpreter/ByteCode.cpp
Boram Bae f11752b532 Update to support new.target with Class and eval (#489)
* Pass more tests

Signed-off-by: Boram Bae <boram21.bae@samsung.com>
2019-10-31 13:38:49 +09:00

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);
}
}