From f11752b5328455ff2c878e3135f045cb5f193f8b Mon Sep 17 00:00:00 2001 From: Boram Bae Date: Thu, 31 Oct 2019 13:38:49 +0900 Subject: [PATCH] Update to support new.target with Class and eval (#489) * Pass more tests Signed-off-by: Boram Bae --- src/interpreter/ByteCode.cpp | 2 +- src/parser/ScriptParser.cpp | 6 ++-- src/parser/ScriptParser.h | 4 +-- src/parser/esprima_cpp/esprima.cpp | 38 +++++++++++++++++++++---- src/parser/esprima_cpp/esprima.h | 2 +- src/runtime/FunctionObject.cpp | 4 +-- src/runtime/GlobalObject.cpp | 10 +++++-- test/vendortest | 2 +- tools/test/spidermonkey/excludelist.txt | 6 +--- 9 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/interpreter/ByteCode.cpp b/src/interpreter/ByteCode.cpp index 42bea8b9a..12b16ebe6 100644 --- a/src/interpreter/ByteCode.cpp +++ b/src/interpreter/ByteCode.cpp @@ -102,7 +102,7 @@ void ByteCodeBlock::fillLocDataIfNeeded(Context* c) 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); + 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; diff --git a/src/parser/ScriptParser.cpp b/src/parser/ScriptParser.cpp index 839cca9b1..b02cfa3a4 100644 --- a/src/parser/ScriptParser.cpp +++ b/src/parser/ScriptParser.cpp @@ -26,6 +26,8 @@ #include "parser/ScriptParser.h" #include "parser/ast/AST.h" #include "parser/CodeBlock.h" +#include "runtime/Environment.h" +#include "runtime/EnvironmentRecord.h" namespace Escargot { @@ -202,7 +204,7 @@ void ScriptParser::generateCodeBlockTreeFromASTWalkerPostProcess(InterpretedCode cb->m_astContext = nullptr; } -ScriptParser::InitializeScriptResult ScriptParser::initializeScript(StringView scriptSource, String* fileName, bool isModule, InterpretedCodeBlock* parentCodeBlock, bool strictFromOutside, bool isEvalCodeInFunction, bool isEvalMode, bool inWithOperation, size_t stackSizeRemain, bool needByteCodeGeneration, bool allowSuperCall, bool allowSuperProperty) +ScriptParser::InitializeScriptResult ScriptParser::initializeScript(StringView scriptSource, String* fileName, bool isModule, InterpretedCodeBlock* parentCodeBlock, bool strictFromOutside, bool isEvalCodeInFunction, bool isEvalMode, bool inWithOperation, size_t stackSizeRemain, bool needByteCodeGeneration, bool allowSuperCall, bool allowSuperProperty, bool allowNewTarget) { GC_disable(); @@ -213,7 +215,7 @@ ScriptParser::InitializeScriptResult ScriptParser::initializeScript(StringView s // Parsing try { InterpretedCodeBlock* topCodeBlock = nullptr; - ProgramNode* programNode = esprima::parseProgram(m_context, scriptSource, isModule, strictFromOutside, inWith, stackSizeRemain, allowSC, allowSP); + ProgramNode* programNode = esprima::parseProgram(m_context, scriptSource, isModule, strictFromOutside, inWith, stackSizeRemain, allowSC, allowSP, allowNewTarget); Script* script = new Script(fileName, new StringView(scriptSource), programNode->moduleData(), !parentCodeBlock); if (parentCodeBlock) { diff --git a/src/parser/ScriptParser.h b/src/parser/ScriptParser.h index 6211fa14b..fea3520ce 100644 --- a/src/parser/ScriptParser.h +++ b/src/parser/ScriptParser.h @@ -58,10 +58,10 @@ class ScriptParser : public gc { } }; - InitializeScriptResult initializeScript(StringView scriptSource, String* fileName, bool isModule, InterpretedCodeBlock* parentCodeBlock, bool strictFromOutside, bool isEvalCodeInFunction, bool isEvalMode, bool inWithOperation, size_t stackSizeRemain, bool needByteCodeGeneration, bool allowSuperCall, bool allowSuperProperty); + InitializeScriptResult initializeScript(StringView scriptSource, String* fileName, bool isModule, InterpretedCodeBlock* parentCodeBlock, bool strictFromOutside, bool isEvalCodeInFunction, bool isEvalMode, bool inWithOperation, size_t stackSizeRemain, bool needByteCodeGeneration, bool allowSuperCall, bool allowSuperProperty, bool allowNewTarget); InitializeScriptResult initializeScript(String* scriptSource, String* fileName, bool isModule, bool strictFromOutside = false, bool isRunningEvalOnFunction = false, bool isEvalMode = false, size_t stackSizeRemain = SIZE_MAX) { - return initializeScript(StringView(scriptSource, 0, scriptSource->length()), fileName, isModule, nullptr, strictFromOutside, isRunningEvalOnFunction, isEvalMode, false, stackSizeRemain, true, false, false); + return initializeScript(StringView(scriptSource, 0, scriptSource->length()), fileName, isModule, nullptr, strictFromOutside, isRunningEvalOnFunction, isEvalMode, false, stackSizeRemain, true, false, false, false); } void generateFunctionByteCode(ExecutionState& state, InterpretedCodeBlock* codeBlock, size_t stackSizeRemain); diff --git a/src/parser/esprima_cpp/esprima.cpp b/src/parser/esprima_cpp/esprima.cpp index fb9d8869e..b696bc456 100644 --- a/src/parser/esprima_cpp/esprima.cpp +++ b/src/parser/esprima_cpp/esprima.cpp @@ -76,6 +76,7 @@ struct Context { bool allowLexicalDeclaration : 1; bool allowSuperCall : 1; bool allowSuperProperty : 1; + bool allowNewTarget : 1; bool isAssignmentTarget : 1; bool isBindingElement : 1; bool inFunctionBody : 1; @@ -221,6 +222,7 @@ class Parser { this->context->allowLexicalDeclaration = false; this->context->allowSuperCall = false; this->context->allowSuperProperty = false; + this->context->allowNewTarget = false; this->context->isAssignmentTarget = true; this->context->isBindingElement = true; this->context->inFunctionBody = false; @@ -1398,11 +1400,13 @@ class Parser { const bool previousAllowYield = this->context->allowYield; const bool previousAllowSuperCall = this->context->allowSuperCall; const bool previousAllowSuperProperty = this->context->allowSuperProperty; + const bool previousAllowNewTarget = this->context->allowNewTarget; const bool previousInArrowFunction = this->context->inArrowFunction; this->context->allowYield = true; this->context->inArrowFunction = false; this->context->allowSuperProperty = true; + this->context->allowNewTarget = true; if (allowSuperCall) { this->context->allowSuperCall = true; @@ -1419,6 +1423,7 @@ class Parser { this->context->allowYield = previousAllowYield; this->context->inArrowFunction = previousInArrowFunction; this->context->allowSuperProperty = previousAllowSuperProperty; + this->context->allowNewTarget = previousAllowNewTarget; this->context->allowSuperCall = previousAllowSuperCall; this->currentScopeContext->m_paramsStartLOC.index = node.index; @@ -1886,7 +1891,7 @@ class Parser { if (this->match(Period)) { this->nextToken(); - if (this->lookahead.type == Token::IdentifierToken && this->context->inFunctionBody && this->lookahead.relatedSource(this->scanner->source) == "target") { + if (this->lookahead.type == Token::IdentifierToken && this->context->allowNewTarget && this->lookahead.relatedSource(this->scanner->source) == "target") { this->nextToken(); this->currentScopeContext->m_hasSuperOrNewTarget = true; MetaNode node = this->createNode(); @@ -4157,8 +4162,11 @@ class Parser { bool previousAllowYield = this->context->allowYield; bool previousInArrowFunction = this->context->inArrowFunction; + bool previousAllowNewTarget = this->context->allowNewTarget; + this->context->allowYield = !isGenerator; this->context->inArrowFunction = false; + this->context->allowNewTarget = true; ParseFormalParametersResult formalParameters; this->parseFormalParameters(newBuilder, formalParameters, &firstRestricted); @@ -4180,6 +4188,7 @@ class Parser { this->context->strict = previousStrict; this->context->allowYield = previousAllowYield; this->context->inArrowFunction = previousInArrowFunction; + this->context->allowNewTarget = previousAllowNewTarget; this->currentScopeContext->m_nodeType = ASTNodeType::FunctionDeclaration; this->currentScopeContext->m_isGenerator = isGenerator; @@ -4205,8 +4214,11 @@ class Parser { bool previousAllowYield = this->context->allowYield; bool previousInArrowFunction = this->context->inArrowFunction; + bool previousAllowNewTarget = this->context->allowNewTarget; + this->context->allowYield = !isGenerator; this->context->inArrowFunction = false; + this->context->allowNewTarget = true; if (!this->match(LeftParenthesis)) { ALLOC_TOKEN(token); @@ -4269,6 +4281,7 @@ class Parser { this->context->strict = previousStrict; this->context->allowYield = previousAllowYield; this->context->inArrowFunction = previousInArrowFunction; + this->context->allowNewTarget = previousAllowNewTarget; this->currentScopeContext->m_nodeType = ASTNodeType::FunctionExpression; this->currentScopeContext->m_isGenerator = isGenerator; @@ -4354,10 +4367,12 @@ class Parser { const bool previousAllowYield = this->context->allowYield; const bool previousInArrowFunction = this->context->inArrowFunction; const bool previousAllowSuperProperty = this->context->allowSuperProperty; + const bool previousAllowNewTarget = this->context->allowNewTarget; this->context->allowYield = true; this->context->inArrowFunction = false; this->context->allowSuperProperty = true; + this->context->allowNewTarget = true; this->expect(LeftParenthesis); this->expect(RightParenthesis); @@ -4371,6 +4386,7 @@ class Parser { this->context->allowYield = previousAllowYield; this->context->inArrowFunction = previousInArrowFunction; this->context->allowSuperProperty = previousAllowSuperProperty; + this->context->allowNewTarget = previousAllowNewTarget; this->currentScopeContext->m_paramsStartLOC.index = node.index; this->currentScopeContext->m_paramsStartLOC.column = node.column; @@ -4398,10 +4414,12 @@ class Parser { const bool previousAllowYield = this->context->allowYield; const bool previousInArrowFunction = this->context->inArrowFunction; const bool previousAllowSuperProperty = this->context->allowSuperProperty; + const bool previousAllowNewTarget = this->context->allowNewTarget; this->context->allowYield = true; this->context->allowSuperProperty = true; this->context->inArrowFunction = false; + this->context->allowNewTarget = true; this->expect(LeftParenthesis); @@ -4420,6 +4438,7 @@ class Parser { this->context->allowYield = previousAllowYield; this->context->allowSuperProperty = previousAllowSuperProperty; this->context->inArrowFunction = previousInArrowFunction; + this->context->allowNewTarget = previousAllowNewTarget; this->currentScopeContext->m_paramsStartLOC.index = node.index; this->currentScopeContext->m_paramsStartLOC.column = node.column; @@ -4447,10 +4466,12 @@ class Parser { const bool previousAllowYield = this->context->allowYield; const bool previousInArrowFunction = this->context->inArrowFunction; const bool previousAllowSuperProperty = this->context->allowSuperProperty; + const bool previousAllowNewTarget = this->context->allowNewTarget; this->context->allowYield = false; this->context->allowSuperProperty = true; this->context->inArrowFunction = false; + this->context->allowNewTarget = true; this->expect(LeftParenthesis); @@ -4464,6 +4485,7 @@ class Parser { this->context->allowYield = previousAllowYield; this->context->allowSuperProperty = previousAllowSuperProperty; this->context->inArrowFunction = previousInArrowFunction; + this->context->allowNewTarget = previousAllowNewTarget; this->currentScopeContext->m_paramsStartLOC.index = node.index; this->currentScopeContext->m_paramsStartLOC.column = node.column; @@ -5198,10 +5220,15 @@ class Parser { { ASSERT(this->isParsingSingleFunction); + const bool previousAllowNewTarget = context->allowNewTarget; + + context->allowNewTarget = true; MetaNode node = this->createNode(); StatementContainer* params = this->parseFunctionParameters(builder); BlockStatementNode* body = this->parseFunctionBody(builder); + context->allowNewTarget = previousAllowNewTarget; + return this->finalize(node, builder.createFunctionNode(params, body, std::move(this->numeralLiteralVector))); } @@ -5276,7 +5303,7 @@ class Parser { } }; -ProgramNode* parseProgram(::Escargot::Context* ctx, StringView source, bool isModule, bool strictFromOutside, bool inWith, size_t stackRemain, bool allowSuperCallOutside, bool allowSuperPropertyOutside) +ProgramNode* parseProgram(::Escargot::Context* ctx, StringView source, bool isModule, bool strictFromOutside, bool inWith, size_t stackRemain, bool allowSuperCallFromOutside, bool allowSuperPropertyFromOutside, bool allowNewTargetFromOutside) { // GC should be disabled during the parsing process ASSERT(GC_is_disabled()); @@ -5287,8 +5314,9 @@ ProgramNode* parseProgram(::Escargot::Context* ctx, StringView source, bool isMo parser.context->strict = strictFromOutside; parser.context->inWith = inWith; - parser.context->allowSuperCall = allowSuperCallOutside; - parser.context->allowSuperProperty = allowSuperPropertyOutside; + parser.context->allowSuperCall = allowSuperCallFromOutside; + parser.context->allowSuperProperty = allowSuperPropertyFromOutside; + parser.context->allowNewTarget = allowNewTargetFromOutside; ProgramNode* nd = parser.parseProgram(builder); return nd; @@ -5307,8 +5335,8 @@ FunctionNode* parseSingleFunction(::Escargot::Context* ctx, InterpretedCodeBlock parser.context->allowLexicalDeclaration = true; parser.context->allowSuperCall = true; parser.context->allowSuperProperty = true; + parser.context->allowNewTarget = true; parser.isParsingSingleFunction = true; - parser.codeBlock = codeBlock; scopeContext = new (ctx->astAllocator()) ASTFunctionScopeContext(ctx->astAllocator(), codeBlock->isStrict()); diff --git a/src/parser/esprima_cpp/esprima.h b/src/parser/esprima_cpp/esprima.h index 6b2e5e3ca..29d57f41d 100644 --- a/src/parser/esprima_cpp/esprima.h +++ b/src/parser/esprima_cpp/esprima.h @@ -61,7 +61,7 @@ struct Error : public gc { #define ESPRIMA_RECURSIVE_LIMIT 1024 -ProgramNode* parseProgram(::Escargot::Context* ctx, StringView source, bool isModule, bool strictFromOutside, bool inWith, size_t stackRemain, bool allowSuperCallOutside, bool allowSuperPropertyOutside); +ProgramNode* parseProgram(::Escargot::Context* ctx, StringView source, bool isModule, bool strictFromOutside, bool inWith, size_t stackRemain, bool allowSuperCallFromOutside, bool allowSuperPropertyFromOutside, bool allowNewTargetFromOutside); FunctionNode* parseSingleFunction(::Escargot::Context* ctx, InterpretedCodeBlock* codeBlock, ASTFunctionScopeContext*& scopeContext, size_t stackRemain); } } diff --git a/src/runtime/FunctionObject.cpp b/src/runtime/FunctionObject.cpp index 7fc77d0db..b432d4817 100644 --- a/src/runtime/FunctionObject.cpp +++ b/src/runtime/FunctionObject.cpp @@ -114,7 +114,7 @@ FunctionObject::FunctionSource FunctionObject::createFunctionSourceFromScriptSou try { srcToTest.appendString(") { }"); String* cur = srcToTest.finalize(&state); - esprima::parseProgram(state.context(), StringView(cur, 0, cur->length()), false, false, false, SIZE_MAX, false, false); + esprima::parseProgram(state.context(), StringView(cur, 0, cur->length()), false, false, false, SIZE_MAX, false, false, true); // reset ASTAllocator state.context()->astAllocator().reset(); @@ -151,7 +151,7 @@ FunctionObject::FunctionSource FunctionObject::createFunctionSourceFromScriptSou ScriptParser parser(state.context()); String* scriptSource = src.finalize(&state); - Script* script = parser.initializeScript(StringView(scriptSource, 0, scriptSource->length()), new ASCIIString("Function Constructor input"), false, nullptr, false, false, false, false, SIZE_MAX, false, allowSuperCall, false).scriptThrowsExceptionIfParseError(state); + Script* script = parser.initializeScript(StringView(scriptSource, 0, scriptSource->length()), new ASCIIString("Function Constructor input"), false, nullptr, false, false, false, false, SIZE_MAX, false, allowSuperCall, false, true).scriptThrowsExceptionIfParseError(state); InterpretedCodeBlock* cb = script->topCodeBlock()->firstChild(); cb->updateSourceElementStart(3, 1); LexicalEnvironment* globalEnvironment = new LexicalEnvironment(new GlobalEnvironmentRecord(state, script->topCodeBlock(), state.context()->globalObject(), &state.context()->globalDeclarativeRecord(), &state.context()->globalDeclarativeStorage()), nullptr); diff --git a/src/runtime/GlobalObject.cpp b/src/runtime/GlobalObject.cpp index da8c6a0cd..7e870810b 100644 --- a/src/runtime/GlobalObject.cpp +++ b/src/runtime/GlobalObject.cpp @@ -156,7 +156,7 @@ Value GlobalObject::eval(ExecutionState& state, const Value& arg) #else size_t stackRemainApprox = STACK_LIMIT_FROM_BASE - (currentStackBase - state.stackBase()); #endif - Script* script = parser.initializeScript(StringView(arg.asString(), 0, arg.asString()->length()), String::fromUTF8(s, strlen(s)), false, nullptr, strictFromOutside, false, true, false, stackRemainApprox, true, false, false).scriptThrowsExceptionIfParseError(state); + Script* script = parser.initializeScript(StringView(arg.asString(), 0, arg.asString()->length()), String::fromUTF8(s, strlen(s)), false, nullptr, strictFromOutside, false, true, false, stackRemainApprox, true, false, false, false).scriptThrowsExceptionIfParseError(state); // In case of indirect call, use global execution context ExecutionState stateForNewGlobal(m_context); return script->execute(stateForNewGlobal, true, script->topCodeBlock()->isStrict()); @@ -192,6 +192,12 @@ Value GlobalObject::evalLocal(ExecutionState& state, const Value& arg, Value thi current = current->parent(); } + bool allowNewTarget = false; + auto thisEnvironment = state.getThisEnvironment(); + if (thisEnvironment->isDeclarativeEnvironmentRecord() && thisEnvironment->asDeclarativeEnvironmentRecord()->isFunctionEnvironmentRecord()) { + allowNewTarget = true; + } + volatile int sp; size_t currentStackBase = (size_t)&sp; #ifdef STACK_GROWS_DOWN @@ -200,7 +206,7 @@ Value GlobalObject::evalLocal(ExecutionState& state, const Value& arg, Value thi size_t stackRemainApprox = STACK_LIMIT_FROM_BASE - (currentStackBase - state.stackBase()); #endif - Script* script = parser.initializeScript(StringView(arg.asString(), 0, arg.asString()->length()), String::fromUTF8(s, sizeof(s) - 1), false, parentCodeBlock, strictFromOutside, isRunningEvalOnFunction, true, inWithOperation, stackRemainApprox, true, parentCodeBlock->allowSuperCall(), parentCodeBlock->allowSuperProperty()).scriptThrowsExceptionIfParseError(state); + Script* script = parser.initializeScript(StringView(arg.asString(), 0, arg.asString()->length()), String::fromUTF8(s, sizeof(s) - 1), false, parentCodeBlock, strictFromOutside, isRunningEvalOnFunction, true, inWithOperation, stackRemainApprox, true, parentCodeBlock->allowSuperCall(), parentCodeBlock->allowSuperProperty(), allowNewTarget).scriptThrowsExceptionIfParseError(state); return script->executeLocal(state, thisValue, parentCodeBlock, script->topCodeBlock()->isStrict(), isRunningEvalOnFunction); } return arg; diff --git a/test/vendortest b/test/vendortest index 36bf26ba4..35e1a2690 160000 --- a/test/vendortest +++ b/test/vendortest @@ -1 +1 @@ -Subproject commit 36bf26ba45e4f87651ab2bdce1122ad5730f07b0 +Subproject commit 35e1a26902b029c0dc60673644268f6935d15859 diff --git a/tools/test/spidermonkey/excludelist.txt b/tools/test/spidermonkey/excludelist.txt index fc333ee82..3d8a7d642 100644 --- a/tools/test/spidermonkey/excludelist.txt +++ b/tools/test/spidermonkey/excludelist.txt @@ -49,6 +49,7 @@ non262/BigInt/decimal.js non262/BigInt/large-bit-length.js non262/BigInt/mod.js non262/BigInt/Number-conversion-rounding.js +non262/class/newTargetDVG.js # These tests include features of ES7 non262/Array/slice-sparse-with-large-index.js @@ -59,11 +60,6 @@ non262/arrow-functions/arrow-not-as-end-of-statement.js # TODO non262/arrow-functions/yield-in-arrow.js non262/class/className.js -non262/class/newTargetArrow.js -non262/class/newTargetDefaults.js -non262/class/newTargetDVG.js -non262/class/newTargetEval.js -non262/class/newTargetGenerators.js non262/class/outerBinding.js non262/class/strictExecution.js non262/class/superCallBaseInvoked.js