Diff
Modified: trunk/LayoutTests/ChangeLog (197032 => 197033)
--- trunk/LayoutTests/ChangeLog 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/LayoutTests/ChangeLog 2016-02-24 17:36:12 UTC (rev 197033)
@@ -1,3 +1,23 @@
+2016-02-24 Skachkov Oleksandr <gskach...@gmail.com>
+
+ [ES6] Arrow function syntax. Emit loading&putting this/super only if they are used in arrow function
+ https://bugs.webkit.org/show_bug.cgi?id=153981
+
+ Reviewed by Saam Barati.
+
+ Added new benchmark tests for invoking arrow function within function, class's constructor and method
+
+ * js/regress/arrowfunction-call-in-class-constructor-expected.txt: Added.
+ * js/regress/arrowfunction-call-in-class-constructor.html: Added.
+ * js/regress/arrowfunction-call-in-class-method-expected.txt: Added.
+ * js/regress/arrowfunction-call-in-class-method.html: Added.
+ * js/regress/arrowfunction-call-in-function-expected.txt: Added.
+ * js/regress/arrowfunction-call-in-function.html: Added.
+ * js/regress/script-tests/arrowfunction-call-in-class-constructor.js: Added.
+ * js/regress/script-tests/arrowfunction-call-in-class-method.js: Added.
+ * js/regress/script-tests/arrowfunction-call-in-function.js: Added.
+ * js/regress/script-tests/arrowfunction-call.js:
+
2016-02-24 Zalan Bujtas <za...@apple.com>
Background of an absolutely positioned inline element inside text-indented parent is positioned statically.
Added: trunk/LayoutTests/js/regress/arrowfunction-call-in-class-constructor-expected.txt (0 => 197033)
--- trunk/LayoutTests/js/regress/arrowfunction-call-in-class-constructor-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/arrowfunction-call-in-class-constructor-expected.txt 2016-02-24 17:36:12 UTC (rev 197033)
@@ -0,0 +1,10 @@
+JSRegress/arrowfunction-call-in-class-constructor
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/regress/arrowfunction-call-in-class-constructor.html (0 => 197033)
--- trunk/LayoutTests/js/regress/arrowfunction-call-in-class-constructor.html (rev 0)
+++ trunk/LayoutTests/js/regress/arrowfunction-call-in-class-constructor.html 2016-02-24 17:36:12 UTC (rev 197033)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/regress/arrowfunction-call-in-class-method-expected.txt (0 => 197033)
--- trunk/LayoutTests/js/regress/arrowfunction-call-in-class-method-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/arrowfunction-call-in-class-method-expected.txt 2016-02-24 17:36:12 UTC (rev 197033)
@@ -0,0 +1,10 @@
+JSRegress/arrowfunction-call-in-class-method
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/regress/arrowfunction-call-in-class-method.html (0 => 197033)
--- trunk/LayoutTests/js/regress/arrowfunction-call-in-class-method.html (rev 0)
+++ trunk/LayoutTests/js/regress/arrowfunction-call-in-class-method.html 2016-02-24 17:36:12 UTC (rev 197033)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/regress/arrowfunction-call-in-function-expected.txt (0 => 197033)
--- trunk/LayoutTests/js/regress/arrowfunction-call-in-function-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/arrowfunction-call-in-function-expected.txt 2016-02-24 17:36:12 UTC (rev 197033)
@@ -0,0 +1,10 @@
+JSRegress/arrowfunction-call-in-function
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/regress/arrowfunction-call-in-function.html (0 => 197033)
--- trunk/LayoutTests/js/regress/arrowfunction-call-in-function.html (rev 0)
+++ trunk/LayoutTests/js/regress/arrowfunction-call-in-function.html 2016-02-24 17:36:12 UTC (rev 197033)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/regress/script-tests/arrowfunction-call-in-class-constructor.js (0 => 197033)
--- trunk/LayoutTests/js/regress/script-tests/arrowfunction-call-in-class-constructor.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/arrowfunction-call-in-class-constructor.js 2016-02-24 17:36:12 UTC (rev 197033)
@@ -0,0 +1,23 @@
+var testValue = 'test-value';
+
+class A {
+ constructor() {
+ this.value = testValue;
+ }
+}
+
+class B extends A {
+ constructor() {
+ super();
+ var arrow = () => testValue;
+ arrow();
+ }
+}
+
+noInline(B);
+
+for (let i = 0; i < 1000000; ++i) {
+ let b = new B();
+ if (b.value != testValue)
+ throw "Error: bad result: " + result;
+}
Added: trunk/LayoutTests/js/regress/script-tests/arrowfunction-call-in-class-method.js (0 => 197033)
--- trunk/LayoutTests/js/regress/script-tests/arrowfunction-call-in-class-method.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/arrowfunction-call-in-class-method.js 2016-02-24 17:36:12 UTC (rev 197033)
@@ -0,0 +1,24 @@
+var testValue = 'test-value';
+
+class A {
+ constructor() {
+ this.value = testValue;
+ }
+
+ getValue () {
+ return this.value;
+ }
+}
+
+class B extends A {
+ getParentValue() {
+ var arrow = () => testValue;
+ return arrow();
+ }
+}
+
+for (let i = 0; i < 100000; ++i) {
+ let b = new B();
+ if (b.getParentValue() != testValue)
+ throw "Error: bad result: " + result;
+}
Added: trunk/LayoutTests/js/regress/script-tests/arrowfunction-call-in-function.js (0 => 197033)
--- trunk/LayoutTests/js/regress/script-tests/arrowfunction-call-in-function.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/arrowfunction-call-in-function.js 2016-02-24 17:36:12 UTC (rev 197033)
@@ -0,0 +1,11 @@
+function bar(a, b) {
+ return ((_a, _b) => _a + _b)(a, b);
+}
+
+noInline(bar);
+
+for (let i = 0; i < 1000000; ++i) {
+ let result = bar(1, 2);
+ if (result != 3)
+ throw "Error: bad result: " + result;
+}
Modified: trunk/LayoutTests/js/regress/script-tests/arrowfunction-call.js (197032 => 197033)
--- trunk/LayoutTests/js/regress/script-tests/arrowfunction-call.js 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/LayoutTests/js/regress/script-tests/arrowfunction-call.js 2016-02-24 17:36:12 UTC (rev 197033)
@@ -8,8 +8,8 @@
noInline(bar);
-for (var i = 0; i < 1000000; ++i) {
- var result = bar(1, 2);
+for (let i = 0; i < 1000000; ++i) {
+ let result = bar(1, 2);
if (result != 3)
throw "Error: bad result: " + result;
}
Modified: trunk/Source/_javascript_Core/ChangeLog (197032 => 197033)
--- trunk/Source/_javascript_Core/ChangeLog 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-02-24 17:36:12 UTC (rev 197033)
@@ -1,3 +1,96 @@
+2016-02-24 Skachkov Oleksandr <gskach...@gmail.com>
+
+ [ES6] Arrow function syntax. Emit loading&putting this/super only if they are used in arrow function
+ https://bugs.webkit.org/show_bug.cgi?id=153981
+
+ Reviewed by Saam Barati.
+
+ In first iteration of implemenation arrow function, we emit load and store variables 'this', 'arguments',
+ 'super', 'new.target' in case if arrow function is exist even variables are not used in arrow function.
+ Current patch added logic that prevent from emiting those varibles if they are not used in arrow function.
+ During syntax analyze parser store information about using variables in arrow function inside of
+ the ordinary function scope and then put to BytecodeGenerator through UnlinkedCodeBlock
+
+ * bytecode/ExecutableInfo.h:
+ (JSC::ExecutableInfo::ExecutableInfo):
+ (JSC::ExecutableInfo::arrowFunctionCodeFeatures):
+ * bytecode/UnlinkedCodeBlock.cpp:
+ (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
+ * bytecode/UnlinkedCodeBlock.h:
+ (JSC::UnlinkedCodeBlock::arrowFunctionCodeFeatures):
+ (JSC::UnlinkedCodeBlock::doAnyInnerArrowFunctionsUseArguments):
+ (JSC::UnlinkedCodeBlock::doAnyInnerArrowFunctionsUseSuperCall):
+ (JSC::UnlinkedCodeBlock::doAnyInnerArrowFunctionsUseSuperProperty):
+ (JSC::UnlinkedCodeBlock::doAnyInnerArrowFunctionsUseEval):
+ (JSC::UnlinkedCodeBlock::doAnyInnerArrowFunctionsUseThis):
+ (JSC::UnlinkedCodeBlock::doAnyInnerArrowFunctionsUseNewTarget):
+ * bytecode/UnlinkedFunctionExecutable.cpp:
+ (JSC::generateUnlinkedFunctionCodeBlock):
+ (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+ * bytecode/UnlinkedFunctionExecutable.h:
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::BytecodeGenerator):
+ (JSC::BytecodeGenerator::initializeArrowFunctionContextScopeIfNeeded):
+ (JSC::BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment):
+ (JSC::BytecodeGenerator::emitLoadThisFromArrowFunctionLexicalEnvironment):
+ (JSC::BytecodeGenerator::emitLoadNewTargetFromArrowFunctionLexicalEnvironment):
+ (JSC::BytecodeGenerator::emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment):
+ (JSC::BytecodeGenerator::isThisUsedInInnerArrowFunction):
+ (JSC::BytecodeGenerator::isArgumentsUsedInInnerArrowFunction):
+ (JSC::BytecodeGenerator::isNewTargetUsedInInnerArrowFunction):
+ (JSC::BytecodeGenerator::isSuperUsedInInnerArrowFunction):
+ (JSC::BytecodeGenerator::emitPutNewTargetToArrowFunctionContextScope):
+ (JSC::BytecodeGenerator::emitPutDerivedConstructorToArrowFunctionContextScope):
+ (JSC::BytecodeGenerator::emitPutThisToArrowFunctionContextScope):
+ * bytecompiler/BytecodeGenerator.h:
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::ThisNode::emitBytecode):
+ (JSC::EvalFunctionCallNode::emitBytecode):
+ (JSC::FunctionCallValueNode::emitBytecode):
+ (JSC::FunctionNode::emitBytecode):
+ * parser/ASTBuilder.h:
+ (JSC::ASTBuilder::createFunctionMetadata):
+ * parser/Nodes.cpp:
+ (JSC::FunctionMetadataNode::FunctionMetadataNode):
+ * parser/Nodes.h:
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::parseGeneratorFunctionSourceElements):
+ (JSC::Parser<LexerType>::parseFunctionBody):
+ (JSC::Parser<LexerType>::parseFunctionInfo):
+ (JSC::Parser<LexerType>::parseProperty):
+ (JSC::Parser<LexerType>::parsePrimaryExpression):
+ (JSC::Parser<LexerType>::parseMemberExpression):
+ * parser/Parser.h:
+ (JSC::Scope::Scope):
+ (JSC::Scope::isArrowFunctionBoundary):
+ (JSC::Scope::innerArrowFunctionFeatures):
+ (JSC::Scope::setInnerArrowFunctionUseSuperCall):
+ (JSC::Scope::setInnerArrowFunctionUseSuperProperty):
+ (JSC::Scope::setInnerArrowFunctionUseEval):
+ (JSC::Scope::setInnerArrowFunctionUseThis):
+ (JSC::Scope::setInnerArrowFunctionUseNewTarget):
+ (JSC::Scope::setInnerArrowFunctionUseArguments):
+ (JSC::Scope::setInnerArrowFunctionUseEvalAndUseArgumentsIfNeeded):
+ (JSC::Scope::collectFreeVariables):
+ (JSC::Scope::mergeInnerArrowFunctionFeatures):
+ (JSC::Scope::fillParametersForSourceProviderCache):
+ (JSC::Scope::restoreFromSourceProviderCache):
+ (JSC::Scope::setIsFunction):
+ (JSC::Scope::setIsArrowFunction):
+ (JSC::Parser::closestParentNonArrowFunctionNonLexicalScope):
+ (JSC::Parser::pushScope):
+ (JSC::Parser::popScopeInternal):
+ * parser/ParserModes.h:
+ * parser/SourceProviderCacheItem.h:
+ (JSC::SourceProviderCacheItem::SourceProviderCacheItem):
+ * parser/SyntaxChecker.h:
+ (JSC::SyntaxChecker::createFunctionMetadata):
+ * tests/stress/arrowfunction-lexical-bind-arguments-non-strict-1.js:
+ * tests/stress/arrowfunction-lexical-bind-arguments-strict.js:
+ * tests/stress/arrowfunction-lexical-bind-newtarget.js:
+ * tests/stress/arrowfunction-lexical-bind-superproperty.js:
+ * tests/stress/arrowfunction-lexical-bind-this-8.js: Added.
+
2016-02-23 Brian Burg <bb...@apple.com>
Web Inspector: teach the Objective-C protocol generators about --frontend and --backend directives
Modified: trunk/Source/_javascript_Core/bytecode/ExecutableInfo.h (197032 => 197033)
--- trunk/Source/_javascript_Core/bytecode/ExecutableInfo.h 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/bytecode/ExecutableInfo.h 2016-02-24 17:36:12 UTC (rev 197033)
@@ -35,7 +35,7 @@
// FIXME: These flags, ParserModes and propagation to XXXCodeBlocks should be reorganized.
// https://bugs.webkit.org/show_bug.cgi?id=151547
struct ExecutableInfo {
- ExecutableInfo(bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, SuperBinding superBinding, SourceParseMode parseMode, DerivedContextType derivedContextType, bool isArrowFunctionContext, bool isClassContext)
+ ExecutableInfo(bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, SuperBinding superBinding, SourceParseMode parseMode, DerivedContextType derivedContextType, bool isArrowFunctionContext, bool isClassContext, ArrowFunctionCodeFeatures arrowFunctionCodeFeatures = NoArrowFunctionFeatures)
: m_usesEval(usesEval)
, m_isStrictMode(isStrictMode)
, m_isConstructor(isConstructor)
@@ -46,6 +46,7 @@
, m_derivedContextType(static_cast<unsigned>(derivedContextType))
, m_isArrowFunctionContext(isArrowFunctionContext)
, m_isClassContext(isClassContext)
+ , m_arrowFunctionCodeFeatures(arrowFunctionCodeFeatures)
{
ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
ASSERT(m_superBinding == static_cast<unsigned>(superBinding));
@@ -61,6 +62,7 @@
DerivedContextType derivedContextType() const { return static_cast<DerivedContextType>(m_derivedContextType); }
bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
bool isClassContext() const { return m_isClassContext; }
+ ArrowFunctionCodeFeatures arrowFunctionCodeFeatures() const { return m_arrowFunctionCodeFeatures; }
private:
unsigned m_usesEval : 1;
@@ -73,6 +75,7 @@
unsigned m_derivedContextType : 2;
unsigned m_isArrowFunctionContext : 1;
unsigned m_isClassContext : 1;
+ ArrowFunctionCodeFeatures m_arrowFunctionCodeFeatures;
};
} // namespace JSC
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.cpp (197032 => 197033)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.cpp 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.cpp 2016-02-24 17:36:12 UTC (rev 197033)
@@ -71,6 +71,7 @@
, m_firstLine(0)
, m_lineCount(0)
, m_endColumn(UINT_MAX)
+ , m_arrowFunctionCodeFeatures(info.arrowFunctionCodeFeatures())
, m_parseMode(info.parseMode())
, m_features(0)
, m_codeType(codeType)
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h (197032 => 197033)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h 2016-02-24 17:36:12 UTC (rev 197033)
@@ -122,6 +122,14 @@
DerivedContextType derivedContextType() const { return static_cast<DerivedContextType>(m_derivedContextType); }
bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
bool isClassContext() const { return m_isClassContext; }
+ ArrowFunctionCodeFeatures arrowFunctionCodeFeatures() const { return m_arrowFunctionCodeFeatures; }
+
+ bool doAnyInnerArrowFunctionsUseArguments() { return m_arrowFunctionCodeFeatures & ArgumentsArrowFunctionFeature; }
+ bool doAnyInnerArrowFunctionsUseSuperCall() { return m_arrowFunctionCodeFeatures & SuperCallArrowFunctionFeature; }
+ bool doAnyInnerArrowFunctionsUseSuperProperty() { return m_arrowFunctionCodeFeatures & SuperPropertyArrowFunctionFeature; }
+ bool doAnyInnerArrowFunctionsUseEval() { return m_arrowFunctionCodeFeatures & EvalArrowFunctionFeature; }
+ bool doAnyInnerArrowFunctionsUseThis() { return m_arrowFunctionCodeFeatures & ThisArrowFunctionFeature; }
+ bool doAnyInnerArrowFunctionsUseNewTarget() { return m_arrowFunctionCodeFeatures & NewTargetArrowFunctionFeature; }
void addExpressionInfo(unsigned instructionOffset, int divot,
int startOffset, int endOffset, unsigned line, unsigned column);
@@ -391,7 +399,8 @@
unsigned m_firstLine;
unsigned m_lineCount;
unsigned m_endColumn;
-
+
+ ArrowFunctionCodeFeatures m_arrowFunctionCodeFeatures;
SourceParseMode m_parseMode;
CodeFeatures m_features;
CodeType m_codeType;
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp (197032 => 197033)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp 2016-02-24 17:36:12 UTC (rev 197033)
@@ -69,7 +69,7 @@
bool isClassContext = executable->superBinding() == SuperBinding::Needed;
UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&vm, FunctionCode,
- ExecutableInfo(function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), executable->superBinding(), parseMode, executable->derivedContextType(), false, isClassContext));
+ ExecutableInfo(function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), executable->superBinding(), parseMode, executable->derivedContextType(), false, isClassContext, executable->arrowFunctionCodeFeatures()));
auto generator(std::make_unique<BytecodeGenerator>(vm, function.get(), result, debuggerMode, profilerMode, executable->parentScopeTDZVariables()));
error = generator->generate();
@@ -101,6 +101,7 @@
, m_superBinding(static_cast<unsigned>(node->superBinding()))
, m_derivedContextType(static_cast<unsigned>(derivedContextType))
, m_sourceParseMode(static_cast<unsigned>(node->parseMode()))
+ , m_arrowFunctionCodeFeatures(node->arrowFunctionCodeFeatures())
, m_name(node->ident())
, m_inferredName(node->inferredName())
, m_sourceOverride(WTFMove(sourceOverride))
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h (197032 => 197033)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h 2016-02-24 17:36:12 UTC (rev 197033)
@@ -84,6 +84,7 @@
FunctionMode functionMode() const { return static_cast<FunctionMode>(m_functionMode); }
ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }
+ ArrowFunctionCodeFeatures arrowFunctionCodeFeatures() const { return m_arrowFunctionCodeFeatures; }
unsigned unlinkedFunctionNameStart() const { return m_unlinkedFunctionNameStart; }
unsigned unlinkedBodyStartColumn() const { return m_unlinkedBodyStartColumn; }
@@ -156,6 +157,7 @@
unsigned m_superBinding : 1;
unsigned m_derivedContextType: 2;
unsigned m_sourceParseMode : 4; // SourceParseMode
+ ArrowFunctionCodeFeatures m_arrowFunctionCodeFeatures;
WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall;
WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct;
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (197032 => 197033)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2016-02-24 17:36:12 UTC (rev 197033)
@@ -243,7 +243,7 @@
bool shouldCaptureSomeOfTheThings = m_shouldEmitDebugHooks || functionNode->needsActivation() || containsArrowOrEvalButNotInArrowBlock;
bool shouldCaptureAllOfTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval();
- bool needsArguments = (functionNode->usesArguments() || codeBlock->usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction()));
+ bool needsArguments = (functionNode->usesArguments() || codeBlock->usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction() && isArgumentsUsedInInnerArrowFunction()));
// Generator never provides "arguments". "arguments" reference will be resolved in an upper generator function scope.
if (parseMode == SourceParseMode::GeneratorBodyMode)
@@ -572,7 +572,7 @@
// Loading |this| inside an arrow function must be done after initializeDefaultParameterValuesAndSetupFunctionScopeStack()
// because that function sets up the SymbolTable stack and emitLoadThisFromArrowFunctionLexicalEnvironment()
// consults the SymbolTable stack
- if (SourceParseMode::ArrowFunctionMode == parseMode && (functionNode->usesThis() || isDerivedClassContext() || isDerivedConstructorContext()))
+ if (SourceParseMode::ArrowFunctionMode == parseMode && (functionNode->usesThis() || isThisUsedInInnerArrowFunction()))
emitLoadThisFromArrowFunctionLexicalEnvironment();
if (needsToUpdateArrowFunctionContext() && !codeBlock->isArrowFunction()) {
@@ -888,16 +888,18 @@
if (!m_codeBlock->isArrowFunction()) {
ScopeOffset offset;
+
+ if (isThisUsedInInnerArrowFunction()) {
+ offset = symbolTable->takeNextScopeOffset();
+ symbolTable->set(propertyNames().thisIdentifier.impl(), SymbolTableEntry(VarOffset(offset)));
+ }
- offset = symbolTable->takeNextScopeOffset();
- symbolTable->set(propertyNames().thisIdentifier.impl(), SymbolTableEntry(VarOffset(offset)));
-
- if (m_codeType == FunctionCode) {
+ if (m_codeType == FunctionCode && isNewTargetUsedInInnerArrowFunction()) {
offset = symbolTable->takeNextScopeOffset();
symbolTable->set(propertyNames().newTargetLocalPrivateName.impl(), SymbolTableEntry(VarOffset(offset)));
}
- if (isConstructor() && constructorKind() == ConstructorKind::Derived) {
+ if (isConstructor() && constructorKind() == ConstructorKind::Derived && isSuperUsedInInnerArrowFunction()) {
offset = symbolTable->takeNextScopeOffset();
symbolTable->set(propertyNames().derivedConstructorPrivateName.impl(), SymbolTableEntry(VarOffset(offset)));
}
@@ -907,28 +909,33 @@
}
VariableEnvironment environment;
- auto addResult = environment.add(propertyNames().thisIdentifier);
- addResult.iterator->value.setIsCaptured();
- addResult.iterator->value.setIsConst();
+
+ if (isThisUsedInInnerArrowFunction()) {
+ auto addResult = environment.add(propertyNames().thisIdentifier);
+ addResult.iterator->value.setIsCaptured();
+ addResult.iterator->value.setIsConst();
+ }
- if (m_codeType == FunctionCode) {
+ if (m_codeType == FunctionCode && isNewTargetUsedInInnerArrowFunction()) {
auto addTarget = environment.add(propertyNames().newTargetLocalPrivateName);
addTarget.iterator->value.setIsCaptured();
addTarget.iterator->value.setIsLet();
}
- if (isConstructor() && constructorKind() == ConstructorKind::Derived) {
+ if (isConstructor() && constructorKind() == ConstructorKind::Derived && isSuperUsedInInnerArrowFunction()) {
auto derivedConstructor = environment.add(propertyNames().derivedConstructorPrivateName);
derivedConstructor.iterator->value.setIsCaptured();
derivedConstructor.iterator->value.setIsLet();
}
- size_t size = m_symbolTableStack.size();
- pushLexicalScopeInternal(environment, TDZCheckOptimization::Optimize, NestedScopeType::IsNotNested, nullptr, TDZRequirement::UnderTDZ, ScopeType::LetConstScope, ScopeRegisterType::Block);
+ if (environment.size() > 0) {
+ size_t size = m_symbolTableStack.size();
+ pushLexicalScopeInternal(environment, TDZCheckOptimization::Optimize, NestedScopeType::IsNotNested, nullptr, TDZRequirement::UnderTDZ, ScopeType::LetConstScope, ScopeRegisterType::Block);
- ASSERT_UNUSED(size, m_symbolTableStack.size() == size + 1);
+ ASSERT_UNUSED(size, m_symbolTableStack.size() == size + 1);
- m_arrowFunctionContextLexicalEnvironmentRegister = m_symbolTableStack.last().m_scope;
+ m_arrowFunctionContextLexicalEnvironmentRegister = m_symbolTableStack.last().m_scope;
+ }
}
RegisterID* BytecodeGenerator::initializeNextParameter()
@@ -4000,16 +4007,16 @@
m_forInContextStack.removeLast();
}
-RegisterID* BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment()
+RegisterID* BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment(const Identifier& identifier)
{
ASSERT(m_codeBlock->isArrowFunction() || m_codeBlock->isArrowFunctionContext() || constructorKind() == ConstructorKind::Derived);
- return emitResolveScope(nullptr, variable(propertyNames().thisIdentifier, ThisResolutionType::Scoped));
+ return emitResolveScope(nullptr, variable(identifier, ThisResolutionType::Scoped));
}
void BytecodeGenerator::emitLoadThisFromArrowFunctionLexicalEnvironment()
{
- emitGetFromScope(thisRegister(), emitLoadArrowFunctionLexicalEnvironment(), variable(propertyNames().thisIdentifier, ThisResolutionType::Scoped), DoNotThrowIfNotFound);
+ emitGetFromScope(thisRegister(), emitLoadArrowFunctionLexicalEnvironment(propertyNames().thisIdentifier), variable(propertyNames().thisIdentifier, ThisResolutionType::Scoped), DoNotThrowIfNotFound);
}
RegisterID* BytecodeGenerator::emitLoadNewTargetFromArrowFunctionLexicalEnvironment()
@@ -4017,7 +4024,7 @@
m_isNewTargetLoadedInArrowFunction = true;
Variable newTargetVar = variable(propertyNames().newTargetLocalPrivateName);
- emitMove(m_newTargetRegister, emitGetFromScope(newTemporary(), emitLoadArrowFunctionLexicalEnvironment(), newTargetVar, ThrowIfNotFound));
+ emitMove(m_newTargetRegister, emitGetFromScope(newTemporary(), emitLoadArrowFunctionLexicalEnvironment(propertyNames().newTargetLocalPrivateName), newTargetVar, ThrowIfNotFound));
return m_newTargetRegister;
}
@@ -4025,35 +4032,61 @@
RegisterID* BytecodeGenerator::emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment()
{
Variable protoScopeVar = variable(propertyNames().derivedConstructorPrivateName);
- return emitGetFromScope(newTemporary(), emitLoadArrowFunctionLexicalEnvironment(), protoScopeVar, ThrowIfNotFound);
+ return emitGetFromScope(newTemporary(), emitLoadArrowFunctionLexicalEnvironment(propertyNames().derivedConstructorPrivateName), protoScopeVar, ThrowIfNotFound);
}
+bool BytecodeGenerator::isThisUsedInInnerArrowFunction()
+{
+ return m_codeBlock->doAnyInnerArrowFunctionsUseThis() || m_codeBlock->doAnyInnerArrowFunctionsUseSuperProperty() || m_codeBlock->doAnyInnerArrowFunctionsUseSuperCall() || m_codeBlock->doAnyInnerArrowFunctionsUseEval() || m_codeBlock->usesEval();
+}
+
+bool BytecodeGenerator::isArgumentsUsedInInnerArrowFunction()
+{
+ return m_codeBlock->doAnyInnerArrowFunctionsUseArguments() || m_codeBlock->doAnyInnerArrowFunctionsUseEval();
+}
+
+bool BytecodeGenerator::isNewTargetUsedInInnerArrowFunction()
+{
+ return m_codeBlock->doAnyInnerArrowFunctionsUseNewTarget() || m_codeBlock->doAnyInnerArrowFunctionsUseSuperCall();
+}
+
+bool BytecodeGenerator::isSuperUsedInInnerArrowFunction()
+{
+ return m_codeBlock->doAnyInnerArrowFunctionsUseSuperCall() || m_codeBlock->doAnyInnerArrowFunctionsUseSuperProperty();
+}
+
void BytecodeGenerator::emitPutNewTargetToArrowFunctionContextScope()
{
- ASSERT(m_arrowFunctionContextLexicalEnvironmentRegister != nullptr);
+ if (isNewTargetUsedInInnerArrowFunction()) {
+ ASSERT(m_arrowFunctionContextLexicalEnvironmentRegister);
- Variable newTargetVar = variable(propertyNames().newTargetLocalPrivateName);
- emitPutToScope(m_arrowFunctionContextLexicalEnvironmentRegister, newTargetVar, newTarget(), DoNotThrowIfNotFound, Initialization);
+ Variable newTargetVar = variable(propertyNames().newTargetLocalPrivateName);
+ emitPutToScope(m_arrowFunctionContextLexicalEnvironmentRegister, newTargetVar, newTarget(), DoNotThrowIfNotFound, Initialization);
+ }
}
void BytecodeGenerator::emitPutDerivedConstructorToArrowFunctionContextScope()
{
if ((isConstructor() && constructorKind() == ConstructorKind::Derived) || m_codeBlock->isClassContext()) {
- ASSERT(m_arrowFunctionContextLexicalEnvironmentRegister);
+ if (isSuperUsedInInnerArrowFunction()) {
+ ASSERT(m_arrowFunctionContextLexicalEnvironmentRegister);
- Variable protoScope = variable(propertyNames().derivedConstructorPrivateName);
- emitPutToScope(m_arrowFunctionContextLexicalEnvironmentRegister, protoScope, &m_calleeRegister, DoNotThrowIfNotFound, Initialization);
+ Variable protoScope = variable(propertyNames().derivedConstructorPrivateName);
+ emitPutToScope(m_arrowFunctionContextLexicalEnvironmentRegister, protoScope, &m_calleeRegister, DoNotThrowIfNotFound, Initialization);
+ }
}
}
-
+
void BytecodeGenerator::emitPutThisToArrowFunctionContextScope()
{
- ASSERT(isDerivedConstructorContext() || m_arrowFunctionContextLexicalEnvironmentRegister != nullptr);
+ if (isThisUsedInInnerArrowFunction()) {
+ ASSERT(isDerivedConstructorContext() || m_arrowFunctionContextLexicalEnvironmentRegister != nullptr);
- Variable thisVar = variable(propertyNames().thisIdentifier, ThisResolutionType::Scoped);
- RegisterID* scope = isDerivedConstructorContext() ? emitLoadArrowFunctionLexicalEnvironment() : m_arrowFunctionContextLexicalEnvironmentRegister;
+ Variable thisVar = variable(propertyNames().thisIdentifier, ThisResolutionType::Scoped);
+ RegisterID* scope = isDerivedConstructorContext() ? emitLoadArrowFunctionLexicalEnvironment(propertyNames().thisIdentifier) : m_arrowFunctionContextLexicalEnvironmentRegister;
- emitPutToScope(scope, thisVar, thisRegister(), DoNotThrowIfNotFound, NotInitialization);
+ emitPutToScope(scope, thisVar, thisRegister(), ThrowIfNotFound, NotInitialization);
+ }
}
void BytecodeGenerator::pushStructureForInScope(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister)
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (197032 => 197033)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2016-02-24 17:36:12 UTC (rev 197033)
@@ -494,7 +494,7 @@
void emitProfileControlFlow(int);
- RegisterID* emitLoadArrowFunctionLexicalEnvironment();
+ RegisterID* emitLoadArrowFunctionLexicalEnvironment(const Identifier&);
void emitLoadThisFromArrowFunctionLexicalEnvironment();
RegisterID* emitLoadNewTargetFromArrowFunctionLexicalEnvironment();
@@ -717,8 +717,13 @@
RegisterID* emitGetParentScope(RegisterID* dst, RegisterID* scope);
void emitPushFunctionNameScope(const Identifier& property, RegisterID* value, bool isCaptured);
void emitNewFunctionExpressionCommon(RegisterID*, BaseFuncExprNode*);
+
+ bool isNewTargetUsedInInnerArrowFunction();
+ bool isSuperUsedInInnerArrowFunction();
+ bool isArgumentsUsedInInnerArrowFunction();
public:
+ bool isThisUsedInInnerArrowFunction();
void pushLexicalScope(VariableEnvironmentNode*, TDZCheckOptimization, NestedScopeType = NestedScopeType::IsNotNested, RegisterID** constantSymbolTableResult = nullptr);
void popLexicalScope(VariableEnvironmentNode*);
void prepareLexicalScopeForNextForLoopIteration(VariableEnvironmentNode*, RegisterID* loopSymbolTable);
Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (197032 => 197033)
--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2016-02-24 17:36:12 UTC (rev 197033)
@@ -146,7 +146,7 @@
RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext())
+ if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext() && generator.isThisUsedInInnerArrowFunction())
generator.emitLoadThisFromArrowFunctionLexicalEnvironment();
if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived || generator.isDerivedConstructorContext())
@@ -723,7 +723,7 @@
// eval("this.id = 'B'");
// }
// }
- if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext())
+ if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext() && generator.isThisUsedInInnerArrowFunction())
generator.emitLoadThisFromArrowFunctionLexicalEnvironment();
Variable var = generator.variable(generator.propertyNames().eval);
@@ -762,7 +762,7 @@
bool isConstructorKindDerived = generator.constructorKind() == ConstructorKind::Derived;
if (generator.isDerivedConstructorContext() || (isConstructorKindDerived && generator.needsToUpdateArrowFunctionContext()))
generator.emitPutThisToArrowFunctionContextScope();
-
+
return ret;
}
generator.emitLoad(callArguments.thisRegister(), jsUndefined());
@@ -3138,7 +3138,7 @@
// If there is no return we must automatically insert one.
if (!returnNode) {
- if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext())
+ if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext() && generator.isThisUsedInInnerArrowFunction())
generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); // Arrow function can invoke 'super' in constructor and before leave constructor we need load 'this' from lexical arrow function environment
RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (197032 => 197033)
--- trunk/Source/_javascript_Core/parser/ASTBuilder.h 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h 2016-02-24 17:36:12 UTC (rev 197033)
@@ -372,12 +372,12 @@
const JSTokenLocation& startLocation, const JSTokenLocation& endLocation,
unsigned startColumn, unsigned endColumn, int functionKeywordStart,
int functionNameStart, int parametersStart, bool inStrictContext,
- ConstructorKind constructorKind, SuperBinding superBinding, unsigned parameterCount, SourceParseMode mode, bool isArrowFunctionBodyExpression)
+ ConstructorKind constructorKind, SuperBinding superBinding, unsigned parameterCount, SourceParseMode mode, bool isArrowFunctionBodyExpression, ArrowFunctionCodeFeatures arrowFunctionCodeFeatures = NoArrowFunctionFeatures)
{
return new (m_parserArena) FunctionMetadataNode(
m_parserArena, startLocation, endLocation, startColumn, endColumn,
functionKeywordStart, functionNameStart, parametersStart,
- inStrictContext, constructorKind, superBinding, parameterCount, mode, isArrowFunctionBodyExpression);
+ inStrictContext, constructorKind, superBinding, parameterCount, mode, isArrowFunctionBodyExpression, arrowFunctionCodeFeatures);
}
ExpressionNode* createArrowFunctionExpr(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
Modified: trunk/Source/_javascript_Core/parser/Nodes.cpp (197032 => 197033)
--- trunk/Source/_javascript_Core/parser/Nodes.cpp 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/parser/Nodes.cpp 2016-02-24 17:36:12 UTC (rev 197033)
@@ -146,7 +146,7 @@
ParserArena&, const JSTokenLocation& startLocation,
const JSTokenLocation& endLocation, unsigned startColumn, unsigned endColumn,
int functionKeywordStart, int functionNameStart, int parametersStart, bool isInStrictContext,
- ConstructorKind constructorKind, SuperBinding superBinding, unsigned parameterCount, SourceParseMode mode, bool isArrowFunctionBodyExpression)
+ ConstructorKind constructorKind, SuperBinding superBinding, unsigned parameterCount, SourceParseMode mode, bool isArrowFunctionBodyExpression, ArrowFunctionCodeFeatures arrowFunctionCodeFeatures)
: Node(endLocation)
, m_startColumn(startColumn)
, m_endColumn(endColumn)
@@ -160,6 +160,7 @@
, m_superBinding(static_cast<unsigned>(superBinding))
, m_constructorKind(static_cast<unsigned>(constructorKind))
, m_isArrowFunctionBodyExpression(isArrowFunctionBodyExpression)
+ , m_arrowFunctionCodeFeatures(arrowFunctionCodeFeatures)
{
ASSERT(m_superBinding == static_cast<unsigned>(superBinding));
ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
Modified: trunk/Source/_javascript_Core/parser/Nodes.h (197032 => 197033)
--- trunk/Source/_javascript_Core/parser/Nodes.h 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/parser/Nodes.h 2016-02-24 17:36:12 UTC (rev 197033)
@@ -1824,7 +1824,7 @@
ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end,
unsigned startColumn, unsigned endColumn, int functionKeywordStart,
int functionNameStart, int parametersStart, bool isInStrictContext,
- ConstructorKind, SuperBinding, unsigned, SourceParseMode, bool isArrowFunctionBodyExpression);
+ ConstructorKind, SuperBinding, unsigned, SourceParseMode, bool isArrowFunctionBodyExpression, ArrowFunctionCodeFeatures = NoArrowFunctionFeatures);
void finishParsing(const SourceCode&, const Identifier&, FunctionMode);
@@ -1852,6 +1852,7 @@
SuperBinding superBinding() { return static_cast<SuperBinding>(m_superBinding); }
ConstructorKind constructorKind() { return static_cast<ConstructorKind>(m_constructorKind); }
bool isArrowFunctionBodyExpression() const { return m_isArrowFunctionBodyExpression; }
+ ArrowFunctionCodeFeatures arrowFunctionCodeFeatures() const { return m_arrowFunctionCodeFeatures;}
void setLoc(unsigned firstLine, unsigned lastLine, int startOffset, int lineStartOffset)
{
@@ -1879,6 +1880,7 @@
unsigned m_superBinding : 1;
unsigned m_constructorKind : 2;
unsigned m_isArrowFunctionBodyExpression : 1;
+ ArrowFunctionCodeFeatures m_arrowFunctionCodeFeatures;
};
class FunctionNode final : public ScopeNode {
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (197032 => 197033)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2016-02-24 17:36:12 UTC (rev 197033)
@@ -519,7 +519,7 @@
failIfFalse(parseSourceElements(generatorFunctionContext, mode), "Cannot parse the body of a generator");
popScope(generatorBodyScope, TreeBuilder::NeedsFreeVariableInfo);
}
- info.body = context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, tokenColumn(), functionKeywordStart, functionNameStart, parametersStart, strictMode(), ConstructorKind::None, m_superBinding, info.parameterCount, SourceParseMode::GeneratorBodyMode, false);
+ info.body = context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, tokenColumn(), functionKeywordStart, functionNameStart, parametersStart, strictMode(), ConstructorKind::None, m_superBinding, info.parameterCount, SourceParseMode::GeneratorBodyMode, false, currentFunctionScope()->innerArrowFunctionFeatures());
info.endLine = tokenLine();
info.endOffset = m_token.m_data.offset;
@@ -1735,7 +1735,7 @@
next();
if (match(CLOSEBRACE)) {
unsigned endColumn = tokenColumn();
- return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, superBinding, parameterCount, parseMode, isArrowFunctionBodyExpression);
+ return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, superBinding, parameterCount, parseMode, isArrowFunctionBodyExpression, currentFunctionScope()->innerArrowFunctionFeatures());
}
}
@@ -1747,7 +1747,7 @@
else
failIfFalse(parseSourceElements(syntaxChecker, CheckForStrictMode), bodyType == StandardFunctionBodyBlock ? "Cannot parse body of this function" : "Cannot parse body of this arrow function");
unsigned endColumn = tokenColumn();
- return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, superBinding, parameterCount, parseMode, isArrowFunctionBodyExpression);
+ return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, superBinding, parameterCount, parseMode, isArrowFunctionBodyExpression, currentFunctionScope()->innerArrowFunctionFeatures());
}
static const char* stringForFunctionMode(SourceParseMode mode)
@@ -1988,7 +1988,7 @@
functionInfo.body = context.createFunctionMetadata(
startLocation, endLocation, functionInfo.bodyStartColumn, bodyEndColumn,
functionKeywordStart, functionNameStart, parametersStart,
- cachedInfo->strictMode, constructorKind, expectedSuperBinding, cachedInfo->parameterCount, mode, functionBodyType == ArrowFunctionBodyExpression);
+ cachedInfo->strictMode, constructorKind, expectedSuperBinding, cachedInfo->parameterCount, mode, functionBodyType == ArrowFunctionBodyExpression, cachedInfo->innerArrowFunctionFeatures);
functionScope->restoreFromSourceProviderCache(cachedInfo);
popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
@@ -2064,12 +2064,18 @@
: closestParentNonArrowFunctionNonLexicalScope()->constructorKind();
semanticFailIfTrue(functionConstructorKind == ConstructorKind::None, "Cannot call super() outside of a class constructor");
semanticFailIfTrue(functionConstructorKind != ConstructorKind::Derived, "Cannot call super() in a base class constructor");
+
+ if (functionBodyType == ArrowFunctionBodyBlock || functionBodyType == ArrowFunctionBodyExpression)
+ functionScope->setInnerArrowFunctionUseSuperCall();
}
if (functionScope->needsSuperBinding()) {
SuperBinding functionSuperBinding = functionBodyType == StandardFunctionBodyBlock
? expectedSuperBinding
: closestParentNonArrowFunctionNonLexicalScope()->expectedSuperBinding();
semanticFailIfTrue(functionSuperBinding == SuperBinding::NotNeeded, "super can only be used in a method of a derived class");
+
+ if (functionBodyType == ArrowFunctionBodyBlock || functionBodyType == ArrowFunctionBodyExpression)
+ functionScope->setInnerArrowFunctionUseSuperProperty();
}
}
@@ -3207,6 +3213,8 @@
JSTextPosition start = tokenStartPosition();
JSTokenLocation location(tokenLocation());
currentScope()->useVariable(ident, m_vm->propertyNames->eval == *ident);
+ if (currentScope()->isArrowFunction())
+ currentScope()->setInnerArrowFunctionUseEval();
TreeExpression node = context.createResolve(location, *ident, start, lastTokenEndPosition());
return context.createProperty(ident, node, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Shorthand), PropertyNode::KnownDirect, complete);
}
@@ -3620,6 +3628,8 @@
case THISTOKEN: {
JSTokenLocation location(tokenLocation());
next();
+ if (currentScope()->isArrowFunction())
+ currentScope()->setInnerArrowFunctionUseThis();
return context.createThisExpr(location, m_thisTDZMode);
}
case IDENT: {
@@ -3795,6 +3805,8 @@
if (m_vm->propertyNames->target == *ident) {
semanticFailIfFalse(currentScope()->isFunction(), "new.target is only valid inside functions");
baseIsNewTarget = true;
+ if (currentScope()->isArrowFunction())
+ currentScope()->setInnerArrowFunctionUseNewTarget();
base = context.createNewTargetExpr(location);
newCount--;
next();
Modified: trunk/Source/_javascript_Core/parser/Parser.h (197032 => 197033)
--- trunk/Source/_javascript_Core/parser/Parser.h 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/parser/Parser.h 2016-02-24 17:36:12 UTC (rev 197033)
@@ -158,7 +158,7 @@
};
struct Scope {
- Scope(const VM* vm, bool isFunction, bool isGenerator, bool strictMode)
+ Scope(const VM* vm, bool isFunction, bool isGenerator, bool strictMode, bool isArrowFunction)
: m_vm(vm)
, m_shadowsArguments(false)
, m_usesEval(false)
@@ -170,7 +170,8 @@
, m_strictMode(strictMode)
, m_isFunction(isFunction)
, m_isGenerator(isGenerator)
- , m_isArrowFunction(false)
+ , m_isArrowFunction(isArrowFunction)
+ , m_isArrowFunctionBoundary(false)
, m_isLexicalScope(false)
, m_isFunctionBoundary(false)
, m_isValidStrictMode(true)
@@ -179,6 +180,7 @@
, m_expectedSuperBinding(static_cast<unsigned>(SuperBinding::NotNeeded))
, m_loopDepth(0)
, m_switchDepth(0)
+ , m_innerArrowFunctionFeatures(0)
{
}
@@ -195,6 +197,7 @@
, m_isFunction(rhs.m_isFunction)
, m_isGenerator(rhs.m_isGenerator)
, m_isArrowFunction(rhs.m_isArrowFunction)
+ , m_isArrowFunctionBoundary(rhs.m_isArrowFunctionBoundary)
, m_isLexicalScope(rhs.m_isLexicalScope)
, m_isFunctionBoundary(rhs.m_isFunctionBoundary)
, m_isValidStrictMode(rhs.m_isValidStrictMode)
@@ -203,6 +206,7 @@
, m_expectedSuperBinding(rhs.m_expectedSuperBinding)
, m_loopDepth(rhs.m_loopDepth)
, m_switchDepth(rhs.m_switchDepth)
+ , m_innerArrowFunctionFeatures(rhs.m_innerArrowFunctionFeatures)
, m_moduleScopeData(rhs.m_moduleScopeData)
{
if (rhs.m_labels) {
@@ -465,6 +469,7 @@
void setNeedsFullActivation() { m_needsFullActivation = true; }
bool needsFullActivation() const { return m_needsFullActivation; }
+ bool isArrowFunctionBoundary() { return m_isArrowFunctionBoundary; }
bool isArrowFunction() { return m_isArrowFunction; }
bool hasDirectSuper() { return m_hasDirectSuper; }
@@ -473,11 +478,31 @@
bool needsSuperBinding() { return m_needsSuperBinding; }
void setNeedsSuperBinding() { m_needsSuperBinding = true; }
+ ArrowFunctionCodeFeatures innerArrowFunctionFeatures() { return m_innerArrowFunctionFeatures; }
+
void setExpectedSuperBinding(SuperBinding superBinding) { m_expectedSuperBinding = static_cast<unsigned>(superBinding); }
SuperBinding expectedSuperBinding() const { return static_cast<SuperBinding>(m_expectedSuperBinding); }
void setConstructorKind(ConstructorKind constructorKind) { m_constructorKind = static_cast<unsigned>(constructorKind); }
ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
+ void setInnerArrowFunctionUseSuperCall() { m_innerArrowFunctionFeatures |= SuperCallArrowFunctionFeature; }
+ void setInnerArrowFunctionUseSuperProperty() { m_innerArrowFunctionFeatures |= SuperPropertyArrowFunctionFeature; }
+ void setInnerArrowFunctionUseEval() { m_innerArrowFunctionFeatures |= EvalArrowFunctionFeature; }
+ void setInnerArrowFunctionUseThis() { m_innerArrowFunctionFeatures |= ThisArrowFunctionFeature; }
+ void setInnerArrowFunctionUseNewTarget() { m_innerArrowFunctionFeatures |= NewTargetArrowFunctionFeature; }
+ void setInnerArrowFunctionUseArguments() { m_innerArrowFunctionFeatures |= ArgumentsArrowFunctionFeature; }
+
+ void setInnerArrowFunctionUseEvalAndUseArgumentsIfNeeded()
+ {
+ ASSERT(m_isArrowFunction);
+
+ if (m_usesEval)
+ setInnerArrowFunctionUseEval();
+
+ if (m_usedVariables.contains(m_vm->propertyNames->arguments.impl()))
+ setInnerArrowFunctionUseArguments();
+ }
+
void collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
{
if (nestedScope->m_usesEval)
@@ -489,7 +514,7 @@
continue;
// "arguments" reference should be resolved at function boudary.
- if (nestedScope->isFunctionBoundary() && nestedScope->hasArguments() && impl == m_vm->propertyNames->arguments.impl() && !nestedScope->isArrowFunction())
+ if (nestedScope->isFunctionBoundary() && nestedScope->hasArguments() && impl == m_vm->propertyNames->arguments.impl() && !nestedScope->isArrowFunctionBoundary())
continue;
m_usedVariables.add(impl);
@@ -518,6 +543,11 @@
}
}
+ void mergeInnerArrowFunctionFeatures(ArrowFunctionCodeFeatures arrowFunctionCodeFeatures)
+ {
+ m_innerArrowFunctionFeatures = m_innerArrowFunctionFeatures | arrowFunctionCodeFeatures;
+ }
+
void getCapturedVars(IdentifierSet& capturedVariables, bool& modifiedParameter, bool& modifiedArguments)
{
if (m_needsFullActivation || m_usesEval) {
@@ -568,6 +598,7 @@
parameters.usesEval = m_usesEval;
parameters.strictMode = m_strictMode;
parameters.needsFullActivation = m_needsFullActivation;
+ parameters.innerArrowFunctionFeatures = m_innerArrowFunctionFeatures;
copyCapturedVariablesToVector(m_writtenVariables, parameters.writtenVariables);
copyCapturedVariablesToVector(m_usedVariables, parameters.usedVariables);
}
@@ -577,6 +608,7 @@
ASSERT(m_isFunction);
m_usesEval = info->usesEval;
m_strictMode = info->strictMode;
+ m_innerArrowFunctionFeatures = info->innerArrowFunctionFeatures;
m_needsFullActivation = info->needsFullActivation;
for (unsigned i = 0; i < info->usedVariablesCount; ++i)
m_usedVariables.add(info->usedVariables()[i]);
@@ -592,6 +624,8 @@
m_hasArguments = true;
setIsLexicalScope();
m_isGenerator = false;
+ m_isArrowFunctionBoundary = false;
+ m_isArrowFunction = false;
}
void setIsGeneratorFunction()
@@ -610,6 +644,7 @@
void setIsArrowFunction()
{
setIsFunction();
+ m_isArrowFunctionBoundary = true;
m_isArrowFunction = true;
}
@@ -630,6 +665,7 @@
bool m_isFunction : 1;
bool m_isGenerator : 1;
bool m_isArrowFunction : 1;
+ bool m_isArrowFunctionBoundary : 1;
bool m_isLexicalScope : 1;
bool m_isFunctionBoundary : 1;
bool m_isValidStrictMode : 1;
@@ -638,6 +674,7 @@
unsigned m_expectedSuperBinding : 2;
int m_loopDepth;
int m_switchDepth;
+ ArrowFunctionCodeFeatures m_innerArrowFunctionFeatures;
typedef Vector<ScopeLabelInfo, 2> LabelStack;
std::unique_ptr<LabelStack> m_labels;
@@ -896,9 +933,8 @@
{
unsigned i = m_scopeStack.size() - 1;
ASSERT(i < m_scopeStack.size() && m_scopeStack.size());
- while (i && (!m_scopeStack[i].isFunctionBoundary() || m_scopeStack[i].isArrowFunction()))
+ while (i && (!m_scopeStack[i].isFunctionBoundary() || m_scopeStack[i].isArrowFunctionBoundary()))
i--;
- // When reaching the top level scope (it can be non function scope), we return it.
return ScopeRef(&m_scopeStack, i);
}
@@ -907,12 +943,14 @@
bool isFunction = false;
bool isStrict = false;
bool isGenerator = false;
+ bool isArrowFunction = false;
if (!m_scopeStack.isEmpty()) {
isStrict = m_scopeStack.last().strictMode();
isFunction = m_scopeStack.last().isFunction();
isGenerator = m_scopeStack.last().isGenerator();
+ isArrowFunction = m_scopeStack.last().isArrowFunction();
}
- m_scopeStack.append(Scope(m_vm, isFunction, isGenerator, isStrict));
+ m_scopeStack.append(Scope(m_vm, isFunction, isGenerator, isStrict, isArrowFunction));
return currentScope();
}
@@ -921,6 +959,13 @@
ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
ASSERT(m_scopeStack.size() > 1);
m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
+
+ if (m_scopeStack.last().isArrowFunction())
+ m_scopeStack.last().setInnerArrowFunctionUseEvalAndUseArgumentsIfNeeded();
+
+ if (!(m_scopeStack.last().isFunctionBoundary() && !m_scopeStack.last().isArrowFunctionBoundary()))
+ m_scopeStack[m_scopeStack.size() - 2].mergeInnerArrowFunctionFeatures(m_scopeStack.last().innerArrowFunctionFeatures());
+
if (!m_scopeStack.last().isFunctionBoundary() && m_scopeStack.last().needsFullActivation())
m_scopeStack[m_scopeStack.size() - 2].setNeedsFullActivation();
m_scopeStack.removeLast();
Modified: trunk/Source/_javascript_Core/parser/ParserModes.h (197032 => 197033)
--- trunk/Source/_javascript_Core/parser/ParserModes.h 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/parser/ParserModes.h 2016-02-24 17:36:12 UTC (rev 197033)
@@ -161,6 +161,17 @@
const CodeFeatures AllFeatures = EvalFeature | ArgumentsFeature | WithFeature | ThisFeature | StrictModeFeature | ShadowsArgumentsFeature | ModifiedParameterFeature | ArrowFunctionFeature | ArrowFunctionContextFeature;
+typedef uint8_t ArrowFunctionCodeFeatures;
+
+const ArrowFunctionCodeFeatures NoArrowFunctionFeatures = 0;
+const ArrowFunctionCodeFeatures EvalArrowFunctionFeature = 1 << 0;
+const ArrowFunctionCodeFeatures ArgumentsArrowFunctionFeature = 1 << 1;
+const ArrowFunctionCodeFeatures ThisArrowFunctionFeature = 1 << 2;
+const ArrowFunctionCodeFeatures SuperCallArrowFunctionFeature = 1 << 3;
+const ArrowFunctionCodeFeatures SuperPropertyArrowFunctionFeature = 1 << 4;
+const ArrowFunctionCodeFeatures NewTargetArrowFunctionFeature = 1 << 5;
+
+const ArrowFunctionCodeFeatures AllArrowFunctionCodeFeatures = EvalArrowFunctionFeature | ArgumentsArrowFunctionFeature | ThisArrowFunctionFeature | SuperCallArrowFunctionFeature | SuperPropertyArrowFunctionFeature | NewTargetArrowFunctionFeature;
} // namespace JSC
#endif // ParserModes_h
Modified: trunk/Source/_javascript_Core/parser/SourceProviderCacheItem.h (197032 => 197033)
--- trunk/Source/_javascript_Core/parser/SourceProviderCacheItem.h 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/parser/SourceProviderCacheItem.h 2016-02-24 17:36:12 UTC (rev 197033)
@@ -44,6 +44,7 @@
bool needsFullActivation;
bool usesEval;
bool strictMode;
+ ArrowFunctionCodeFeatures innerArrowFunctionFeatures;
Vector<RefPtr<UniquedStringImpl>> usedVariables;
Vector<RefPtr<UniquedStringImpl>> writtenVariables;
bool isBodyArrowExpression { false };
@@ -87,6 +88,8 @@
bool usesEval : 1;
bool strictMode : 1;
+
+ ArrowFunctionCodeFeatures innerArrowFunctionFeatures;
unsigned lastTockenLineStartOffset;
unsigned usedVariablesCount;
@@ -127,6 +130,7 @@
, parameterCount(parameters.parameterCount)
, usesEval(parameters.usesEval)
, strictMode(parameters.strictMode)
+ , innerArrowFunctionFeatures(parameters.innerArrowFunctionFeatures)
, lastTockenLineStartOffset(parameters.lastTockenLineStartOffset)
, usedVariablesCount(parameters.usedVariables.size())
, writtenVariablesCount(parameters.writtenVariables.size())
Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (197032 => 197033)
--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2016-02-24 17:36:12 UTC (rev 197033)
@@ -183,7 +183,7 @@
ExpressionType createYield(const JSTokenLocation&, ExpressionType, bool, int, int, int) { return YieldExpr; }
ClassExpression createClassExpr(const JSTokenLocation&, const Identifier&, VariableEnvironment&, ExpressionType, ExpressionType, PropertyList, PropertyList) { return ClassExpr; }
ExpressionType createFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
- int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, SuperBinding, unsigned, SourceParseMode, bool) { return FunctionBodyResult; }
+ int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, SuperBinding, unsigned, SourceParseMode, bool, ArrowFunctionCodeFeatures = NoArrowFunctionFeatures) { return FunctionBodyResult; }
ExpressionType createArrowFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
void setFunctionNameStart(int, int) { }
int createArguments() { return ArgumentsResult; }
Modified: trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-arguments-non-strict-1.js (197032 => 197033)
--- trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-arguments-non-strict-1.js 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-arguments-non-strict-1.js 2016-02-24 17:36:12 UTC (rev 197033)
@@ -214,3 +214,39 @@
for (var i = 0; i < 10000; i++) {
testCase(boo('A' + i)('B' + i)('D' + i)('E' + i)('G' + i)[0], 'E' + i, txtMsg + "#17");
}
+
+var testValue = 'test-value';
+
+function f_args () {
+ if (true) {
+ let someValue = '';
+ if (true) {
+ let anotherValue = 'value';
+ return () => () => () => arguments[0];
+ }
+ }
+
+ return () => 'no-value';
+}
+
+for (var i = 0; i < 10000; i++) {
+ let v = f_args(testValue, 'anotherValue')()()();
+ testCase(v, testValue);
+}
+
+function f_args_eval () {
+ if (true) {
+ let someValue = '';
+ if (true) {
+ let anotherValue = 'value';
+ return () => () => () => eval('arguments[0]');
+ }
+ }
+
+ return () => 'no-value';
+}
+
+for (var i = 0; i < 10000; i++) {
+ let v = f_args_eval(testValue, 'anotherValue')()()();
+ testCase(v, testValue);
+}
Modified: trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-arguments-strict.js (197032 => 197033)
--- trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-arguments-strict.js 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-arguments-strict.js 2016-02-24 17:36:12 UTC (rev 197033)
@@ -131,3 +131,39 @@
}
test();
+
+var testValue = 'test-value';
+
+function f_args () {
+ if (true) {
+ let someValue = '';
+ if (true) {
+ let anotherValue = 'value';
+ return () => () => () => arguments[0];
+ }
+ }
+
+ return () => 'no-value';
+}
+
+for (var i = 0; i < 10000; i++) {
+ let v = f_args(testValue, 'anotherValue')()()();
+ testCase(v, testValue);
+}
+
+function f_args_eval () {
+ if (true) {
+ let someValue = '';
+ if (true) {
+ let anotherValue = 'value';
+ return () => () => () => eval('arguments[0]');
+ }
+ }
+
+ return () => 'no-value';
+}
+
+for (var i = 0; i < 10000; i++) {
+ let v = f_args_eval(testValue, 'anotherValue')()()();
+ testCase(v, testValue);
+}
Modified: trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-newtarget.js (197032 => 197033)
--- trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-newtarget.js 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-newtarget.js 2016-02-24 17:36:12 UTC (rev 197033)
@@ -66,7 +66,7 @@
new C(val);
}
catch (e) {
- result = e instanceof ReferenceError;
+ result = e instanceof ReferenceError;
}
return result;
@@ -76,3 +76,17 @@
testCase(tryToCreateClass(true), true, "Error: newTargetLocal should be hided variable");
testCase(tryToCreateClass(false), true, "Error: newTargetLocal should be hided variable");
}
+
+function getTargetBlockScope() {
+ if (true) {
+ let someValue = '';
+ if (true)
+ return x => new.target;
+ }
+ return ()=>value;
+}
+
+for (var i = 0; i < 1000; i++) {
+ var undefinedTarget = getTargetBlockScope()()
+ testCase(undefinedTarget, undefined, "Error: new.target is not lexically binded inside of the arrow function #4");
+}
Modified: trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-superproperty.js (197032 => 197033)
--- trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-superproperty.js 2016-02-24 17:26:52 UTC (rev 197032)
+++ trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-superproperty.js 2016-02-24 17:36:12 UTC (rev 197033)
@@ -123,6 +123,20 @@
getParentValue() {
return super.getValue();
}
+
+ getValueBlockScope() {
+ if (true) {
+ var someValue ='';
+ if (true) {
+ return () => {
+ if (true) {
+ let internalValue = '';
+ return super.getValue();
+ }
+ }
+ }
+ }
+ }
};
var g = new G();
@@ -141,6 +155,8 @@
let setValue = g1.setValueCB();
setValue('new-value');
testCase(getValue(), 'new-value', 'Error: Some problem with using arrow and "super" inside of the method that retun arrow function');
+ getValue = g1.getValueBlockScope();
+ testCase(getValue(), 'new-value', 'Error: Some problem with using arrow and "super" with deep nesting inside of the method that retun arrow function');
}
var H = class H extends A {
Added: trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-this-8.js (0 => 197033)
--- trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-this-8.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-this-8.js 2016-02-24 17:36:12 UTC (rev 197033)
@@ -0,0 +1,89 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+let testValue = 'test-value';
+
+var f_this = function () {
+ let value = 'value';
+ if (true) {
+ let someValue = 'someValue';
+ if (true) {
+ let = anotherValue = 'value';
+ return () => () => () => this.value;
+ }
+ }
+
+ return () => value;
+}
+
+for (let i = 0; i < 10000; i++) {
+ testCase(f_this.call({value : testValue})()()(), testValue);
+}
+
+var f_this_eval = function () {
+ if (true) {
+ let someValue = '';
+ if (true) {
+ let = anotherValue = 'value';
+ return () => () => () => eval('this.value');
+ }
+ }
+
+ return () => 'no-value';
+}
+
+for (let i = 0; i < 10000; i++) {
+ testCase(f_this_eval.call({value : testValue}, false)()()(), testValue);
+}
+
+
+function f_this_branches (branch, returnThis) {
+ let value = 'value';
+ if (branch === 'A') {
+ let someValue = 'someValue';
+ if (true) {
+ let = anotherValue = 'value';
+ return () => () => () => {
+ if (returnThis)
+ return this.value;
+ else
+ return anotherValue;
+ }
+ }
+ }
+
+ return () => value;
+}
+
+for (let i = 0; i < 10000; i++) {
+ testCase(f_this_branches.call({value : testValue}, 'B')() == testValue, false);
+ testCase(f_this_branches.call({value : testValue}, 'A', false)()()() == testValue, false);
+ testCase(f_this_branches.call({value : testValue}, 'A', true)()()(), testValue);
+}
+
+function f_this_eval_branches (branch, returnThis) {
+ let value = 'value';
+ if (branch === 'A') {
+ let someValue = 'someValue';
+ if (true) {
+ let = anotherValue = 'value';
+ return () => () => () => {
+ if (returnThis)
+ return eval('this.value');
+ else
+ return anotherValue;
+ }
+ }
+ }
+
+ return () => value;
+}
+
+for (let i = 0; i < 10000; i++) {
+ testCase(f_this_eval_branches.call({value : testValue}, 'B')() == testValue, false);
+ testCase(f_this_eval_branches.call({value : testValue}, 'A', false)()()() == testValue, false);
+ testCase(f_this_eval_branches.call({value : testValue}, 'A', true)()()(), testValue);
+}