Ignore:
Timestamp:
Dec 1, 2015, 1:46:12 AM (10 years ago)
Author:
[email protected]
Message:

[ES6] "super" and "this" should be lexically bound inside an arrow function and should live in a JSLexicalEnvironment
https://bugs.webkit.org/show_bug.cgi?id=149338

Source/JavaScriptCore:

Patch by Aleksandr Skachkov <[email protected]> on 2015-12-01
Reviewed by Saam Barati.

Implemented new version of the lexically bound 'this' in arrow function. In current version
'this' is stored inside of the lexical environment of the function. To store and load we use
op_get_from_scope and op_put_to_scope operations. Also new implementation prevent raising TDZ
error for arrow functions that are declared before super() but invoke after.

  • builtins/BuiltinExecutables.cpp:

(JSC::createExecutableInternal):

  • bytecode/BytecodeList.json:
  • bytecode/BytecodeUseDef.h:
  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):

  • bytecode/EvalCodeCache.h:

(JSC::EvalCodeCache::getSlow):

  • bytecode/ExecutableInfo.h:

(JSC::ExecutableInfo::ExecutableInfo):
(JSC::ExecutableInfo::isDerivedConstructorContext):
(JSC::ExecutableInfo::isArrowFunctionContext):

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):

  • bytecode/UnlinkedCodeBlock.h:

(JSC::UnlinkedCodeBlock::isDerivedConstructorContext):
(JSC::UnlinkedCodeBlock::isArrowFunctionContext):

  • bytecode/UnlinkedFunctionExecutable.cpp:

(JSC::generateUnlinkedFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):

  • bytecode/UnlinkedFunctionExecutable.h:
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::initializeArrowFunctionContextScopeIfNeeded):
(JSC::BytecodeGenerator::variable):
(JSC::BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment):
(JSC::BytecodeGenerator::emitLoadThisFromArrowFunctionLexicalEnvironment):
(JSC::BytecodeGenerator::emitLoadNewTargetFromArrowFunctionLexicalEnvironment):
(JSC::BytecodeGenerator::emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment):
(JSC::BytecodeGenerator::emitPutNewTargetToArrowFunctionContextScope):
(JSC::BytecodeGenerator::emitPutDerivedConstructorToArrowFunctionContextScope):
(JSC::BytecodeGenerator::emitPutThisToArrowFunctionContextScope):

  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::isDerivedConstructorContext):
(JSC::BytecodeGenerator::usesArrowFunction):
(JSC::BytecodeGenerator::needsToUpdateArrowFunctionContext):
(JSC::BytecodeGenerator::usesEval):
(JSC::BytecodeGenerator::usesThis):
(JSC::BytecodeGenerator::newTarget):
(JSC::BytecodeGenerator::makeFunction):

  • bytecompiler/NodesCodegen.cpp:

(JSC::ThisNode::emitBytecode):
(JSC::SuperNode::emitBytecode):
(JSC::EvalFunctionCallNode::emitBytecode):
(JSC::FunctionCallValueNode::emitBytecode):
(JSC::FunctionNode::emitBytecode):

  • debugger/DebuggerCallFrame.cpp:

(JSC::DebuggerCallFrame::evaluate):

  • dfg/DFGAbstractInterpreterInlines.h:
  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCapabilities.cpp:
  • dfg/DFGClobberize.h:
  • dfg/DFGDoesGC.cpp:
  • dfg/DFGFixupPhase.cpp:
  • dfg/DFGNodeType.h:
  • dfg/DFGObjectAllocationSinkingPhase.cpp:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGPromotedHeapLocation.cpp:
  • dfg/DFGPromotedHeapLocation.h:
  • dfg/DFGSafeToExecute.h:
  • dfg/DFGSpeculativeJIT.cpp:
  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT32_64.cpp:
  • dfg/DFGSpeculativeJIT64.cpp:
  • ftl/FTLCapabilities.cpp:
  • ftl/FTLLowerDFGToLLVM.cpp:
  • ftl/FTLOperations.cpp:

(JSC::FTL::operationMaterializeObjectInOSR):

  • interpreter/Interpreter.cpp:

(JSC::eval):

  • jit/JIT.cpp:
  • jit/JIT.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emitNewFuncExprCommon):

  • jit/JITOpcodes32_64.cpp:
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createArrowFunctionExpr):
(JSC::ASTBuilder::usesArrowFunction):

  • parser/Nodes.h:

(JSC::ScopeNode::usesArrowFunction):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseFunctionInfo):

  • parser/ParserModes.h:
  • runtime/CodeCache.cpp:

(JSC::CodeCache::getGlobalCodeBlock):
(JSC::CodeCache::getProgramCodeBlock):
(JSC::CodeCache::getEvalCodeBlock):
(JSC::CodeCache::getModuleProgramCodeBlock):
(JSC::CodeCache::getFunctionExecutableFromGlobalCode):

  • runtime/CodeCache.h:
  • runtime/CommonIdentifiers.h:
  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

  • runtime/Executable.cpp:

(JSC::ScriptExecutable::ScriptExecutable):
(JSC::EvalExecutable::create):
(JSC::EvalExecutable::EvalExecutable):
(JSC::ProgramExecutable::ProgramExecutable):
(JSC::ModuleProgramExecutable::ModuleProgramExecutable):
(JSC::FunctionExecutable::FunctionExecutable):

  • runtime/Executable.h:

(JSC::ScriptExecutable::isArrowFunctionContext):
(JSC::ScriptExecutable::isDerivedConstructorContext):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::createEvalCodeBlock):

  • runtime/JSGlobalObject.h:
  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncEval):

  • tests/es6.yaml:
  • tests/stress/arrowfunction-activation-sink-osrexit.js:
  • tests/stress/arrowfunction-activation-sink.js:
  • tests/stress/arrowfunction-lexical-bind-newtarget.js: Added.
  • tests/stress/arrowfunction-lexical-bind-supercall-1.js: Added.
  • tests/stress/arrowfunction-lexical-bind-supercall-2.js: Added.
  • tests/stress/arrowfunction-lexical-bind-supercall-3.js: Added.
  • tests/stress/arrowfunction-lexical-bind-supercall-4.js: Added.
  • tests/stress/arrowfunction-lexical-bind-this-1.js:
  • tests/stress/arrowfunction-lexical-bind-this-7.js: Added.
  • tests/stress/arrowfunction-tdz-1.js: Added.
  • tests/stress/arrowfunction-tdz-2.js: Added.
  • tests/stress/arrowfunction-tdz-3.js: Added.
  • tests/stress/arrowfunction-tdz-4.js: Added.
  • tests/stress/arrowfunction-tdz.js: Removed.

LayoutTests:

Patch by Skachkov Oleksandr <[email protected]> on 2015-12-01
Reviewed by Saam Barati.

  • js/arrowfunction-supercall-expected.txt: Added.
  • js/arrowfunction-supercall.html: Added.
  • js/arrowfunction-tdz-expected.txt: Added new expectation.
  • js/script-tests/arrowfunction-supercall.js: Added.
  • js/script-tests/arrowfunction-tdz.js: Added new cases.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r192814 r192876  
    146146RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    147147{
    148     if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived)
     148    if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext())
     149        generator.emitLoadThisFromArrowFunctionLexicalEnvironment();
     150   
     151    if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived || generator.isDerivedConstructorContext())
    149152        generator.emitTDZCheck(generator.thisRegister());
    150153
     
    165168        return 0;
    166169
    167     RegisterID callee;
    168     callee.setIndex(JSStack::Callee);
    169 
    170     return generator.emitGetById(generator.finalDestination(dst), &callee, generator.propertyNames().underscoreProto);
     170    RegisterID* scopeId;
     171    if (generator.isDerivedConstructorContext())
     172        scopeId = generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment();
     173    else {
     174        RegisterID callee;
     175        callee.setIndex(JSStack::Callee);
     176
     177        scopeId = &callee;
     178    }
     179   
     180    return generator.emitGetById(generator.finalDestination(dst), scopeId, generator.propertyNames().underscoreProto);
    171181}
    172182
     
    692702RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    693703{
     704    // We need try to load 'this' before call eval in constructor, because 'this' can created by 'super' in some of the arrow function
     705    // var A = class A {
     706    //   constructor () { this.id = 'A'; }
     707    // }
     708    //
     709    // var B = class B extend A {
     710    //    constructor () {
     711    //       var arrow = () => super();
     712    //       arrow();
     713    //       eval("this.id = 'B'");
     714    //    }
     715    // }
     716    if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext())
     717        generator.emitLoadThisFromArrowFunctionLexicalEnvironment();
     718
    694719    Variable var = generator.variable(generator.propertyNames().eval);
    695720    if (RegisterID* local = var.local()) {
     
    719744    CallArguments callArguments(generator, m_args);
    720745    if (m_expr->isSuperNode()) {
    721         ASSERT(generator.isConstructor());
    722         ASSERT(generator.constructorKind() == ConstructorKind::Derived);
     746        ASSERT(generator.isConstructor() || generator.isDerivedConstructorContext());
     747        ASSERT(generator.constructorKind() == ConstructorKind::Derived || generator.isDerivedConstructorContext());
    723748        generator.emitMove(callArguments.thisRegister(), generator.newTarget());
    724749        RegisterID* ret = generator.emitConstruct(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
    725750        generator.emitMove(generator.thisRegister(), ret);
     751       
     752        bool isConstructorKindDerived = generator.constructorKind() == ConstructorKind::Derived;
     753        if (generator.isDerivedConstructorContext() || (isConstructorKindDerived && generator.needsToUpdateArrowFunctionContext()))
     754            generator.emitPutThisToArrowFunctionContextScope();
     755       
    726756        return ret;
    727757    }
     
    29813011    // If there is no return we must automatically insert one.
    29823012    if (!returnNode) {
     3013        if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext())
     3014            generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); // Arrow function can invoke 'super' in constructor and before leave constructor we need load 'this' from lexical arrow function environment
     3015
    29833016        RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
    29843017        generator.emitProfileType(r0, ProfileTypeBytecodeFunctionReturnStatement); // Do not emit expression info for this profile because it's not in the user's source code.
Note: See TracChangeset for help on using the changeset viewer.