Ignore:
Timestamp:
Mar 4, 2021, 4:18:23 PM (4 years ago)
Author:
[email protected]
Message:

Don't trust parsing information to tell us if we've emitted op_call_eval
https://bugs.webkit.org/show_bug.cgi?id=222694
rdar://74778016

Reviewed by Yusuke Suzuki.

JSTests:

  • stress/eval-liveness-should-not-come-from-parser.js: Added.

(foo):

Source/JavaScriptCore:

In the DFG, op_call_eval can't be inlined. Not inlining is required for how
eval is currently implemented in the DFG. For CodeBlocks with eval in them,
the scope register is also alive everywhere.

When doing spread of arguments in eval, we end up emitting a call varargs
instead of a direct eval. This seems like a spec bug:
https://bugs.webkit.org/show_bug.cgi?id=222671

However, this leads to something that had eval textually in it leading to
us reporting the scope register is always alive, even if op_call_eval isn't
in the bytecode stream. This leads to a validation error, since the DFG
isn't actually keeping this scope register alive everywhere, because
op_call_eval isn't in the bytecode stream.

This patch fixes this by having a bit indicating if op_call_eval is in
the bytecode stream or not.

  • bytecode/BytecodeUseDef.h:

(JSC::computeUsesForBytecodeIndex):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::usesCallEval const):
(JSC::CodeBlock::usesEval const): Deleted.

  • bytecode/ExecutableInfo.h:

(JSC::ExecutableInfo::ExecutableInfo):
(JSC::ExecutableInfo::usesEval const): Deleted.

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):

  • bytecode/UnlinkedCodeBlock.h:

(JSC::UnlinkedCodeBlock::usesCallEval const):
(JSC::UnlinkedCodeBlock::setUsesCallEval):
(JSC::UnlinkedCodeBlock::usesEval const): Deleted.

  • bytecode/UnlinkedCodeBlockGenerator.h:

(JSC::UnlinkedCodeBlockGenerator::usesCallEval const):
(JSC::UnlinkedCodeBlockGenerator::setUsesCallEval):
(JSC::UnlinkedCodeBlockGenerator::usesEval const): Deleted.

  • bytecode/UnlinkedFunctionExecutable.cpp:

(JSC::generateUnlinkedFunctionCodeBlock):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitCall):
(JSC::BytecodeGenerator::isThisUsedInInnerArrowFunction):
(JSC::BytecodeGenerator::isNewTargetUsedInInnerArrowFunction):
(JSC::BytecodeGenerator::isSuperUsedInInnerArrowFunction):
(JSC::BytecodeGenerator::isSuperCallUsedInInnerArrowFunction):

  • dfg/DFGGraph.h:
  • runtime/CachedTypes.cpp:

(JSC::CachedCodeBlock::usesCallEval const):
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
(JSC::CachedCodeBlock<CodeBlockType>::encode):
(JSC::CachedCodeBlock::usesEval const): Deleted.

  • runtime/CodeCache.cpp:

(JSC::generateUnlinkedCodeBlockImpl):

  • runtime/EvalExecutable.h:

(JSC::EvalExecutable::executableInfo const): Deleted.

  • runtime/ModuleProgramExecutable.h:
  • runtime/ProgramExecutable.h:
  • runtime/ScriptExecutable.h:

(JSC::ScriptExecutable::usesEval const): Deleted.

File:
1 edited

Legend:

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

    r273649 r273931  
    348348    , m_expressionTooDeep(false)
    349349    , m_isBuiltinFunction(codeBlock->isBuiltinFunction())
    350     , m_usesNonStrictEval(codeBlock->usesEval() && !ecmaMode.isStrict())
     350    , m_usesNonStrictEval(functionNode->usesEval() && !ecmaMode.isStrict())
    351351    // FIXME: We should be able to have tail call elimination with the profiler
    352352    // enabled. This is currently not possible because the profiler expects
     
    380380    SourceParseMode parseMode = codeBlock->parseMode();
    381381
    382     bool containsArrowOrEvalButNotInArrowBlock = ((functionNode->usesArrowFunction() && functionNode->doAnyInnerArrowFunctionsUseAnyFeature()) || functionNode->usesEval()) && !m_codeBlock->isArrowFunction();
     382    bool containsArrowOrEvalButNotInArrowBlock = ((functionNode->usesArrowFunction() && functionNode->doAnyInnerArrowFunctionsUseAnyFeature()) || usesEval()) && !m_codeBlock->isArrowFunction();
    383383    bool shouldCaptureSomeOfTheThings = shouldEmitDebugHooks() || functionNode->needsActivation() || containsArrowOrEvalButNotInArrowBlock;
    384384
    385     bool shouldCaptureAllOfTheThings = shouldEmitDebugHooks() || codeBlock->usesEval();
    386     bool needsArguments = ((functionNode->usesArguments() && !codeBlock->isArrowFunction()) || codeBlock->usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction() && isArgumentsUsedInInnerArrowFunction())) && parseMode != SourceParseMode::ClassFieldInitializerMode;
     385    bool shouldCaptureAllOfTheThings = shouldEmitDebugHooks() || usesEval();
     386    bool needsArguments = ((functionNode->usesArguments() && !codeBlock->isArrowFunction()) || usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction() && isArgumentsUsedInInnerArrowFunction())) && parseMode != SourceParseMode::ClassFieldInitializerMode;
    387387
    388388    if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode)) {
     
    446446        ASSERT(parseMode != SourceParseMode::GeneratorBodyMode);
    447447        ASSERT(!isAsyncFunctionBodyParseMode(parseMode));
    448         bool isDynamicScope = functionNameScopeIsDynamic(codeBlock->usesEval(), ecmaMode.isStrict());
     448        bool isDynamicScope = functionNameScopeIsDynamic(usesEval(), ecmaMode.isStrict());
    449449        bool isFunctionNameCaptured = captures(functionNode->ident().impl());
    450450        bool markAsCaptured = isDynamicScope || isFunctionNameCaptured;
     
    643643
    644644
    645     if (functionNode->needsNewTargetRegisterForThisScope() || isNewTargetUsedInInnerArrowFunction() || codeBlock->usesEval())
     645    if (functionNode->needsNewTargetRegisterForThisScope() || isNewTargetUsedInInnerArrowFunction() || usesEval())
    646646        m_newTargetRegister = addVar();
    647647
     
    725725                case ConstructorKind::None: {
    726726                    bool shouldEmitToThis = false;
    727                     if (functionNode->usesThis() || codeBlock->usesEval() || m_scopeNode->doAnyInnerArrowFunctionsUseThis() || m_scopeNode->doAnyInnerArrowFunctionsUseEval())
     727                    if (functionNode->usesThis() || usesEval() || m_scopeNode->doAnyInnerArrowFunctionsUseThis() || m_scopeNode->doAnyInnerArrowFunctionsUseEval())
    728728                        shouldEmitToThis = true;
    729729                    else if ((functionNode->usesSuperProperty() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperProperty()) && !ecmaMode.isStrict()) {
     
    856856    , m_expressionTooDeep(false)
    857857    , m_isBuiltinFunction(false)
    858     , m_usesNonStrictEval(codeBlock->usesEval() && !ecmaMode.isStrict())
     858    , m_usesNonStrictEval(evalNode->usesEval() && !ecmaMode.isStrict())
    859859    , m_inTailPosition(false)
    860860    , m_needsToUpdateArrowFunctionContext(evalNode->usesArrowFunction() || evalNode->usesEval())
     
    932932    moduleEnvironmentSymbolTable->setScopeType(SymbolTable::ScopeType::LexicalScope);
    933933
    934     bool shouldCaptureAllOfTheThings = shouldEmitDebugHooks() || codeBlock->usesEval();
     934    bool shouldCaptureAllOfTheThings = shouldEmitDebugHooks() || usesEval();
    935935    if (shouldCaptureAllOfTheThings)
    936936        moduleProgramNode->varDeclarations().markAllVariablesAsCaptured();
     
    34513451    ASSERT(dst);
    34523452    ASSERT(dst != ignoredResult());
    3453     if constexpr (opcodeID == op_call_eval)
     3453    if constexpr (opcodeID == op_call_eval) {
     3454        m_codeBlock->setUsesCallEval();
    34543455        CallOp::emit(this, dst, func, callArguments.argumentCountIncludingThis(), callArguments.stackOffset(), ecmaMode());
    3455     else
     3456    } else
    34563457        CallOp::emit(this, dst, func, callArguments.argumentCountIncludingThis(), callArguments.stackOffset());
    34573458   
     
    46334634bool BytecodeGenerator::isThisUsedInInnerArrowFunction()
    46344635{
    4635     return m_scopeNode->doAnyInnerArrowFunctionsUseThis() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperProperty() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperCall() || m_scopeNode->doAnyInnerArrowFunctionsUseEval() || m_codeBlock->usesEval();
     4636    return m_scopeNode->doAnyInnerArrowFunctionsUseThis() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperProperty() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperCall() || m_scopeNode->doAnyInnerArrowFunctionsUseEval() || usesEval();
    46364637}
    46374638   
     
    46434644bool BytecodeGenerator::isNewTargetUsedInInnerArrowFunction()
    46444645{
    4645     return m_scopeNode->doAnyInnerArrowFunctionsUseNewTarget() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperCall() || m_scopeNode->doAnyInnerArrowFunctionsUseEval() || m_codeBlock->usesEval();
     4646    return m_scopeNode->doAnyInnerArrowFunctionsUseNewTarget() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperCall() || m_scopeNode->doAnyInnerArrowFunctionsUseEval() || usesEval();
    46464647}
    46474648
    46484649bool BytecodeGenerator::isSuperUsedInInnerArrowFunction()
    46494650{
    4650     return m_scopeNode->doAnyInnerArrowFunctionsUseSuperCall() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperProperty() || m_scopeNode->doAnyInnerArrowFunctionsUseEval() || m_codeBlock->usesEval();
     4651    return m_scopeNode->doAnyInnerArrowFunctionsUseSuperCall() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperProperty() || m_scopeNode->doAnyInnerArrowFunctionsUseEval() || usesEval();
    46514652}
    46524653
    46534654bool BytecodeGenerator::isSuperCallUsedInInnerArrowFunction()
    46544655{
    4655     return m_scopeNode->doAnyInnerArrowFunctionsUseSuperCall() || m_scopeNode->doAnyInnerArrowFunctionsUseEval() || m_codeBlock->usesEval();
     4656    return m_scopeNode->doAnyInnerArrowFunctionsUseSuperCall() || m_scopeNode->doAnyInnerArrowFunctionsUseEval() || usesEval();
    46564657}
    46574658   
Note: See TracChangeset for help on using the changeset viewer.