Changeset 215986 in webkit


Ignore:
Timestamp:
Apr 30, 2017, 7:51:27 AM (8 years ago)
Author:
gskachkov@gmail.com
Message:

Initialize functions too early in an eval
https://bugs.webkit.org/show_bug.cgi?id=161099

Reviewed by Saam Barati.

JSTests:

  • stress/eval-func-decl-with-let-const-class.js: Added.

Source/JavaScriptCore:

Current patch allow to fix problem with scope in function that is
declared within eval. Before scope was set inside Interpretator.cpp and it
was scope where eval is executed, but in this case function would not
see let/const variables and classes declated in eval.
This patch devide declaration and binding in two operation, first just declare
variable with function name, and second bind variable to function with correct
scope

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):

  • bytecompiler/BytecodeGenerator.h:
  • interpreter/Interpreter.cpp:

(JSC::Interpreter::execute):

Location:
trunk
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r215984 r215986  
     12017-04-30  Oleksandr Skachkov  <gskachkov@gmail.com>
     2
     3        We initialize functions too early in an eval
     4        https://bugs.webkit.org/show_bug.cgi?id=161099
     5
     6        Reviewed by Saam Barati.
     7
     8        * stress/eval-func-decl-with-let-const-class.js: Added.
     9
    1102017-04-30  Oleksandr Skachkov  <gskachkov@gmail.com>
    211
  • trunk/Source/JavaScriptCore/ChangeLog

    r215984 r215986  
     12017-04-30  Oleksandr Skachkov  <gskachkov@gmail.com>
     2
     3        We initialize functions too early in an eval
     4        https://bugs.webkit.org/show_bug.cgi?id=161099
     5
     6        Reviewed by Saam Barati.
     7
     8        Current patch allow to fix problem with scope in function that is
     9        declared within eval. Before scope was set inside Interpretator.cpp and it
     10        was scope where eval is executed, but in this case function would not
     11        see let/const variables and classes declated in eval.
     12        This patch devide declaration and binding in two operation, first just declare
     13        variable with function name, and second bind variable to function with correct
     14        scope
     15
     16        * bytecompiler/BytecodeGenerator.cpp:
     17        (JSC::BytecodeGenerator::generate):
     18        (JSC::BytecodeGenerator::BytecodeGenerator):
     19        * bytecompiler/BytecodeGenerator.h:
     20        * interpreter/Interpreter.cpp:
     21        (JSC::Interpreter::execute):
     22
    1232017-04-30  Oleksandr Skachkov  <gskachkov@gmail.com>
    224
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r215984 r215986  
    107107    {
    108108        RefPtr<RegisterID> temp = newTemporary();
    109         RefPtr<RegisterID> globalScope;
     109        RefPtr<RegisterID> tolLevelScope;
    110110        for (auto functionPair : m_functionsToInitialize) {
    111111            FunctionMetadataNode* metadata = functionPair.first;
     
    114114            if (functionType == NormalFunctionVariable)
    115115                initializeVariable(variable(metadata->ident()), temp.get());
    116             else if (functionType == GlobalFunctionVariable) {
    117                 if (!globalScope) {
    118                     // We know this will resolve to the global object because our parser/global initialization code
     116            else if (functionType == TopLevelFunctionVariable) {
     117                if (!tolLevelScope) {
     118                    // We know this will resolve to the top level scope or global object because our parser/global initialization code
    119119                    // doesn't allow let/const/class variables to have the same names as functions.
    120                     RefPtr<RegisterID> globalObjectScope = emitResolveScope(nullptr, Variable(metadata->ident()));
    121                     globalScope = newBlockScopeVariable();
    122                     emitMove(globalScope.get(), globalObjectScope.get());
     120                    // This is a top level function, and it's an error to ever create a top level function
     121                    // name that would resolve to a lexical variable. E.g:
     122                    // ```
     123                    //     function f() {
     124                    //         {
     125                    //             let x;
     126                    //             {
     127                    //             //// error thrown here
     128                    //                  eval("function x(){}");
     129                    //             }
     130                    //         }
     131                    //     }
     132                    // ```
     133                    // Therefore, we're guaranteed to have this resolve to a top level variable.
     134                    RefPtr<RegisterID> tolLevelObjectScope = emitResolveScope(nullptr, Variable(metadata->ident()));
     135                    tolLevelScope = newBlockScopeVariable();
     136                    emitMove(tolLevelScope.get(), tolLevelObjectScope.get());
    123137                }
    124                 emitPutToScope(globalScope.get(), Variable(metadata->ident()), temp.get(), ThrowIfNotFound, InitializationMode::NotInitialization);
     138                emitPutToScope(tolLevelScope.get(), Variable(metadata->ident()), temp.get(), ThrowIfNotFound, InitializationMode::NotInitialization);
    125139            } else
    126140                RELEASE_ASSERT_NOT_REACHED();
     
    208222
    209223    for (auto* function : functionStack)
    210         m_functionsToInitialize.append(std::make_pair(function, GlobalFunctionVariable));
     224        m_functionsToInitialize.append(std::make_pair(function, TopLevelFunctionVariable));
    211225
    212226    if (Options::validateBytecode()) {
     
    765779    emitCheckTraps();
    766780   
    767     for (FunctionMetadataNode* function : evalNode->functionStack())
     781    for (FunctionMetadataNode* function : evalNode->functionStack()) {
    768782        m_codeBlock->addFunctionDecl(makeFunction(function));
     783        m_functionsToInitialize.append(std::make_pair(function, TopLevelFunctionVariable));
     784    }
    769785
    770786    const VariableEnvironment& varDeclarations = evalNode->varDeclarations();
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r215984 r215986  
    11121112        int m_generatorFrameSymbolTableIndex { 0 };
    11131113
    1114         enum FunctionVariableType : uint8_t { NormalFunctionVariable, GlobalFunctionVariable };
     1114        enum FunctionVariableType : uint8_t { NormalFunctionVariable, TopLevelFunctionVariable };
    11151115        Vector<std::pair<FunctionMetadataNode*, FunctionVariableType>> m_functionsToInitialize;
    11161116        bool m_needToInitializeArguments { false };
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r215984 r215986  
    11791179                FunctionExecutable* function = codeBlock->functionDecl(i);
    11801180                PutPropertySlot slot(variableObject);
    1181                 variableObject->methodTable()->put(variableObject, callFrame, function->name(), JSFunction::create(vm, function, scope), slot);
     1181                // We need create this variables because it will be used to emits code by bytecode generator
     1182                variableObject->methodTable()->put(variableObject, callFrame, function->name(), jsUndefined(), slot);
    11821183            }
    11831184        } else {
     
    11881189                    return checkedReturn(throwSyntaxError(callFrame, throwScope, makeString("Can't create duplicate variable in eval: '", String(function->name().impl()), "'")));
    11891190                PutPropertySlot slot(variableObject);
    1190                 variableObject->methodTable()->put(variableObject, callFrame, function->name(), JSFunction::create(vm, function, scope), slot);
     1191                // We need create this variables because it will be used to emits code by bytecode generator
     1192                variableObject->methodTable()->put(variableObject, callFrame, function->name(), jsUndefined(), slot);
    11911193                RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
    11921194            }
Note: See TracChangeset for help on using the changeset viewer.