Ignore:
Timestamp:
Feb 3, 2014, 12:39:38 PM (11 years ago)
Author:
[email protected]
Message:

Simplified name scope creation for function expressions
https://bugs.webkit.org/show_bug.cgi?id=128031

Reviewed by Mark Lam.

Source/JavaScriptCore:

3X speedup on js/regress/script-tests/function-with-eval.js.

We used to emit bytecode to push a name into local scope every
time a function that needed such a name executed. Now, we push the name
into scope once on the function object, and leave it there.

This is faster, and it also reduces the number of variable resolution
modes you have to worry about when thinking about bytecode and the
debugger.

This patch is slightly complicated by the fact that we don't know if
a function needs a name scope until we parse its body. So, there's some
glue code in here to delay filling in a function's scope until we parse
its body for the first time.

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::generateFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):

  • bytecode/UnlinkedCodeBlock.h:

(JSC::UnlinkedFunctionExecutable::functionMode): Renamed
functionNameIsInScopeToggle to functionMode.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator): No need to emit convert_this
when debugging. The debugger will perform the conversion as needed.

(JSC::BytecodeGenerator::resolveCallee):
(JSC::BytecodeGenerator::addCallee): Simplified this code by removing
the "my function needs a name scope, but didn't allocate one" mode.

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::prepareForRepeatCall): Pass a scope slot through to
CodeBlock generation, so we can add a function name scope if the parsed
function body requires one.

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

(JSC::LLInt::setUpCall): Ditto.

  • parser/NodeConstructors.h:

(JSC::FuncExprNode::FuncExprNode):
(JSC::FuncDeclNode::FuncDeclNode):

  • parser/Nodes.cpp:

(JSC::FunctionBodyNode::finishParsing):

  • parser/Nodes.h:

(JSC::FunctionBodyNode::functionMode): Updated for rename.

  • parser/ParserModes.h:

(JSC::functionNameIsInScope):
(JSC::functionNameScopeIsDynamic): Helper functions for reasoning about
how crazy JavaScript language semantics are.

  • runtime/ArrayPrototype.cpp:

(JSC::isNumericCompareFunction):
(JSC::attemptFastSort): Updated for interface changes above.

  • runtime/Executable.cpp:

(JSC::ScriptExecutable::newCodeBlockFor):
(JSC::ScriptExecutable::prepareForExecutionImpl):
(JSC::FunctionExecutable::FunctionExecutable):

  • runtime/Executable.h:

(JSC::ScriptExecutable::prepareForExecution):
(JSC::FunctionExecutable::functionMode):

  • runtime/JSFunction.cpp:

(JSC::JSFunction::addNameScopeIfNeeded):

  • runtime/JSFunction.h:
  • runtime/JSNameScope.h:

(JSC::JSNameScope::create):
(JSC::JSNameScope::JSNameScope): Added machinery for pushing a function
name scope onto a function when we first discover that it's needed.

LayoutTests:

Added a performance regression test.

  • js/regress/function-with-eval-expected.txt: Added.
  • js/regress/function-with-eval.html: Added.
  • js/regress/script-tests/function-with-eval.js: Added.

(foo):
(bar):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/parser/ParserModes.h

    r163225 r163321  
    2828#define ParserModes_h
    2929
     30#include "Identifier.h"
     31
    3032namespace JSC {
    3133
     
    3638enum DebuggerMode { DebuggerOff, DebuggerOn };
    3739
    38 enum FunctionNameIsInScopeToggle { FunctionNameIsNotInScope, FunctionNameIsInScope };
     40enum FunctionMode { FunctionExpression, FunctionDeclaration };
     41
     42inline bool functionNameIsInScope(const Identifier& name, FunctionMode functionMode)
     43{
     44    if (name.isNull())
     45        return false;
     46
     47    if (functionMode != FunctionExpression)
     48        return false;
     49
     50    return true;
     51}
     52
     53inline bool functionNameScopeIsDynamic(bool usesEval, bool isStrictMode)
     54{
     55    // If non-strict eval is in play, a function gets a separate object in the scope chain for its name.
     56    // This enables eval to declare and then delete a name that shadows the function's name.
     57
     58    if (!usesEval)
     59        return false;
     60
     61    if (isStrictMode)
     62        return false;
     63
     64    return true;
     65}
    3966
    4067typedef unsigned CodeFeatures;
Note: See TracChangeset for help on using the changeset viewer.