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):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@163321 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/parser/ParserModes.h b/Source/JavaScriptCore/parser/ParserModes.h
index 4e9a17c..57c9ffb 100644
--- a/Source/JavaScriptCore/parser/ParserModes.h
+++ b/Source/JavaScriptCore/parser/ParserModes.h
@@ -27,6 +27,8 @@
#ifndef ParserModes_h
#define ParserModes_h
+#include "Identifier.h"
+
namespace JSC {
enum JSParserStrictness { JSParseNormal, JSParseStrict };
@@ -35,7 +37,32 @@
enum ProfilerMode { ProfilerOff, ProfilerOn };
enum DebuggerMode { DebuggerOff, DebuggerOn };
-enum FunctionNameIsInScopeToggle { FunctionNameIsNotInScope, FunctionNameIsInScope };
+enum FunctionMode { FunctionExpression, FunctionDeclaration };
+
+inline bool functionNameIsInScope(const Identifier& name, FunctionMode functionMode)
+{
+ if (name.isNull())
+ return false;
+
+ if (functionMode != FunctionExpression)
+ return false;
+
+ return true;
+}
+
+inline bool functionNameScopeIsDynamic(bool usesEval, bool isStrictMode)
+{
+ // If non-strict eval is in play, a function gets a separate object in the scope chain for its name.
+ // This enables eval to declare and then delete a name that shadows the function's name.
+
+ if (!usesEval)
+ return false;
+
+ if (isStrictMode)
+ return false;
+
+ return true;
+}
typedef unsigned CodeFeatures;