[ES6]. Implement Annex B.3.3 function hoisting rules for eval
authorgskachkov@gmail.com <gskachkov@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Apr 2017 19:35:50 +0000 (19:35 +0000)
committergskachkov@gmail.com <gskachkov@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Apr 2017 19:35:50 +0000 (19:35 +0000)
commita60cf9b3d3a11836f1d038a71aea3b2aa01dc436
treea8cef0fbf0f515534fb8e2fc5db60cf4d1fd3246
parent727ca1410dac58154bbc33c12130dcda29ab7cb3
[ES6]. Implement Annex B.3.3 function hoisting rules for eval
https://bugs.webkit.org/show_bug.cgi?id=163208

Reviewed by Saam Barati.

JSTests:

* stress/eval-func-decl-block-scoping-reassign.js: Added.
(assert):
(throw.new.Error.f):
(throw.new.Error):
* stress/eval-func-decl-block-with-remove.js: Added.
(assert):
(foo.boo):
(foo):
* stress/eval-func-decl-block-with-var-and-remove.js: Added.
(assert):
(assertThrow):
(foo):
(boo):
(joo):
(koo):
* stress/eval-func-decl-block-with-var-sinthesize.js: Added.
(assert):
(assertThrow):
(foo):
(boo):
(hoo):
(joo):
(koo):
* stress/eval-func-decl-in-block-scope-and-bind-to-top-eval-scope.js: Added.
* stress/eval-func-decl-in-eval-within-block-with-let.js: Added.
(assert):
(assertThrow):
(foo):
(boo):
(goo):
* stress/eval-func-decl-in-eval-within-with-scope.js: Added.
(assert):
(assertThrow):
(foo):
(boo):
(boo.let.val2):
(boo.let.val3):
* stress/eval-func-decl-in-frozen-global.js: Added.
(assert):
(assertThrow):
(throw.new.Error):
(Object.freeze):
* stress/eval-func-decl-in-global-of-eval.js: Added.
(assert):
(assertThrow):
(bar):
(baz):
(foobar):
* stress/eval-func-decl-in-global.js: Added.
(assert):
(assertThrow):
* stress/eval-func-decl-in-if.js: Added.
(assert):
* stress/eval-func-decl-within-eval-with-reassign-to-var.js: Added.
(assert):
(assertThrow):
(foo):
(boo):
(foobar):
(hoo):
(joo):
(koo):
(loo):
* stress/eval-func-decl-within-eval-without-reassign-to-let.js: Added.
(assert):
(assertThrow):
(foo):
(boo):
(goo):
* stress/variable-under-tdz-eval-tricky.js:
(assert):
* test262.yaml:

Source/JavaScriptCore:

Current patch implements Annex B.3.3 that is related to
hoisting of function declaration in eval.
https://tc39.github.io/ecma262/#sec-web-compat-evaldeclarationinstantiation
Function declaration in eval should create variable with
function name in function scope where eval is invoked
or bind to variable if it declared outside of the eval.
If variable is created it can be removed by 'delete a;' command.
If eval is invoke in block scope that contains let/const
variable with the same name as function declaration
we do not bind. This patch leads to the following behavior:
'''
function foo() {
   {
     print(boo); // undefined
     eval('{ function boo() {}}');
     print(boo); // function boo() {}
   }
   print(boo); // function boo() {}
}

function foobar() {
  {
    let boo = 10;
    print(boo); // 10;
    eval('{ function boo() {}}');
    print(boo); // 10;
  }
  print(boo) // 10
}

function bar() {
   {
      var boo = 10;
      print(boo); // 10
      eval('{ function boo() {} }');
      print(boo); // function boo() {}
   }
   print(boo); // function boo() {}
}

function bas() {
    {
         let boo = 10;
         eval(' { function boo() {} } ');
         print(boo); // 10
    }
    print(boo); //Reference Error
}
'''

Current implementation relies on already implemented
'hoist function in sloppy mode' feature, with small changes.
In short it works in following way: during hoisting of function
with name S in eval, we are looking for first scope that
contains space for variable with name S and if this scope
has var type we bind function there

To implement this feature was added bytecode ops:
op_resolve_scope_for_hoisting_func_decl_in_eval - get variable scope
or return undefined if variable can't be binded there.

There is a corner case, hoist function in eval within catch block,
that is not covered by this patch, and will be fixed in
https://bugs.webkit.org/show_bug.cgi?id=168184

* bytecode/BytecodeDumper.cpp:
(JSC::BytecodeDumper<Block>::dumpBytecode):
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finalizeLLIntInlineCaches):
* bytecode/EvalCodeBlock.h:
(JSC::EvalCodeBlock::functionHoistingCandidate):
(JSC::EvalCodeBlock::numFunctionHoistingCandidates):
* bytecode/UnlinkedEvalCodeBlock.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::hoistSloppyModeFunctionIfNecessary):
(JSC::BytecodeGenerator::emitResolveScopeForHoistingFuncDeclInEval):
* bytecompiler/BytecodeGenerator.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasIdentifier):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileResolveScopeForHoistingFuncDeclInEval):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileResolveScopeForHoistingFuncDeclInEval):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_resolve_scope_for_hoisting_func_decl_in_eval):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_resolve_scope_for_hoisting_func_decl_in_eval):
* llint/LowLevelInterpreter.asm:
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseFunctionDeclarationStatement):
* parser/Parser.h:
(JSC::Scope::getSloppyModeHoistedFunctions):
(JSC::Parser::declareFunction):
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* runtime/EvalExecutable.h:
(JSC::EvalExecutable::numFunctionHoistingCandidates):
(JSC::EvalExecutable::numTopLevelFunctionDecls):
(JSC::EvalExecutable::numberOfFunctionDecls): Deleted.
* runtime/JSScope.cpp:
(JSC::JSScope::resolve):
(JSC::JSScope::resolveScopeForHoistingFuncDeclInEval):
* runtime/JSScope.h:

LayoutTests:

* inspector/runtime/evaluate-CommandLineAPI-expected.txt:
* inspector/runtime/evaluate-CommandLineAPI.html:
* js/parser-syntax-check-expected.txt:
* js/script-tests/parser-syntax-check.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215476 268f45cc-cd09-0410-ab3c-d52691b4dbfc
62 files changed:
JSTests/ChangeLog
JSTests/stress/eval-func-decl-block-scoping-reassign.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-block-with-remove.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-block-with-var-and-remove.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-block-with-var-sinthesize.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-in-block-scope-and-bind-to-top-eval-scope.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-in-eval-within-block-with-let.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-in-eval-within-with-scope.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-in-frozen-global.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-in-global-of-eval.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-in-global.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-in-if.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-within-eval-with-reassign-to-var.js [new file with mode: 0644]
JSTests/stress/eval-func-decl-within-eval-without-reassign-to-let.js [new file with mode: 0644]
JSTests/stress/variable-under-tdz-eval-tricky.js
JSTests/test262.yaml
LayoutTests/ChangeLog
LayoutTests/inspector/runtime/evaluate-CommandLineAPI-expected.txt
LayoutTests/inspector/runtime/evaluate-CommandLineAPI.html
LayoutTests/js/parser-syntax-check-expected.txt
LayoutTests/js/script-tests/parser-syntax-check.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/EvalCodeBlock.h
Source/JavaScriptCore/bytecode/UnlinkedEvalCodeBlock.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.h
Source/JavaScriptCore/runtime/EvalExecutable.h
Source/JavaScriptCore/runtime/JSScope.cpp
Source/JavaScriptCore/runtime/JSScope.h