Source/JavaScriptCore: Rolled back in <http://trac.webkit.org/changeset/127698> with...
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 7 Sep 2012 01:42:53 +0000 (01:42 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 7 Sep 2012 01:42:53 +0000 (01:42 +0000)
fast/dom/HTMLScriptElement/script-reexecution-pretty-diff.html, which
is to make sure that function declarations don't put their names in scope.

Reviewed by Gavin Barraclough.

    Named functions should not allocate scope objects for their names
    https://bugs.webkit.org/show_bug.cgi?id=95659

    Reviewed by Oliver Hunt.

LayoutTests: Rolled back in <http://trac.webkit.org/changeset/127698> with a fix for
fast/dom/HTMLScriptElement/script-reexecution-pretty-diff.html.

Added a more explicit test for the feature I broke in
fast/dom/HTMLScriptElement/script-reexecution-pretty-diff.html.

Reviewed by Gavin Barraclough.

    Named functions should not allocate scope objects for their names
    https://bugs.webkit.org/show_bug.cgi?id=95659

    Reviewed by Oliver Hunt.

* fast/dom/HTMLScriptElement/script-reexecution.html:
* fast/js/function-name-is-in-scope-expected.txt: Added.
* fast/js/function-name-is-in-scope.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@127810 268f45cc-cd09-0410-ab3c-d52691b4dbfc

19 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/js/function-name-is-in-scope-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/function-name-is-in-scope.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JITStubs.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/parser/NodeConstructors.h
Source/JavaScriptCore/parser/Nodes.cpp
Source/JavaScriptCore/parser/Nodes.h
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/runtime/Executable.cpp
Source/JavaScriptCore/runtime/Executable.h
Source/JavaScriptCore/runtime/JSNameScope.h

index 5878bab..cd4993e 100644 (file)
@@ -1,3 +1,22 @@
+2012-09-06  Geoffrey Garen  <ggaren@apple.com>
+
+        Rolled back in <http://trac.webkit.org/changeset/127698> with a fix for
+        fast/dom/HTMLScriptElement/script-reexecution-pretty-diff.html.
+
+        Added a more explicit test for the feature I broke in 
+        fast/dom/HTMLScriptElement/script-reexecution-pretty-diff.html.
+
+        Reviewed by Gavin Barraclough.
+
+            Named functions should not allocate scope objects for their names
+            https://bugs.webkit.org/show_bug.cgi?id=95659
+
+            Reviewed by Oliver Hunt.
+
+        * fast/dom/HTMLScriptElement/script-reexecution.html:
+        * fast/js/function-name-is-in-scope-expected.txt: Added.
+        * fast/js/function-name-is-in-scope.html: Added.
+
 2012-09-06  Tim Horton  <timothy_horton@apple.com>
 
         Unreviewed, revert part of http://trac.webkit.org/changeset/127698
diff --git a/LayoutTests/fast/js/function-name-is-in-scope-expected.txt b/LayoutTests/fast/js/function-name-is-in-scope-expected.txt
new file mode 100644 (file)
index 0000000..aa70669
--- /dev/null
@@ -0,0 +1,7 @@
+This tests verifies the scope of a function's name.
+
+PASS: f.name == 'f' should be true and is.
+PASS: f == 1 should be true and is.
+PASS: g.name == 'g' should be true and is.
+PASS: g == arguments.callee should be true and is.
+
diff --git a/LayoutTests/fast/js/function-name-is-in-scope.html b/LayoutTests/fast/js/function-name-is-in-scope.html
new file mode 100644 (file)
index 0000000..b5890ad
--- /dev/null
@@ -0,0 +1,62 @@
+<p>This tests verifies the scope of a function's name.
+</p>
+<pre id="console"></pre>
+
+<script>
+function log(s)
+{
+       document.getElementById("console").appendChild(document.createTextNode(s + "\n"));
+}
+
+function shouldBe(a, aDescription, b)
+{
+       if (a == b) {
+               log("PASS: " + aDescription + " should be " + b + " and is.");
+               return;
+       }
+       log("FAIL: " + aDescription + " should be " + b + " but instead is " + a + ".");
+}
+
+if (window.testRunner) {
+       testRunner.dumpAsText();
+}
+
+// Function declarations do not put the function's name in scope.
+function f()
+{
+       shouldBe(
+               f.name == 'f',
+               "f.name == 'f'",
+               true
+       );
+
+       f = 1;
+       shouldBe(
+               f == 1,
+               "f == 1",
+               true
+       );
+};
+
+f();
+
+// Function expressions do put the function's name in scope, as a read-only property.
+var g = function g()
+{
+       shouldBe(
+               g.name == 'g',
+               "g.name == 'g'",
+               true
+       );
+
+       g = 1;
+       shouldBe(
+               g == arguments.callee,
+               "g == arguments.callee",
+               true
+       );
+};
+
+g();
+
+</script>
index ebd43bd..cf69253 100644 (file)
@@ -1,3 +1,16 @@
+2012-09-05  Geoffrey Garen  <ggaren@apple.com>
+
+        Rolled back in <http://trac.webkit.org/changeset/127698> with a fix for
+        fast/dom/HTMLScriptElement/script-reexecution-pretty-diff.html, which
+        is to make sure that function declarations don't put their names in scope.
+
+        Reviewed by Gavin Barraclough.
+
+            Named functions should not allocate scope objects for their names
+            https://bugs.webkit.org/show_bug.cgi?id=95659
+
+            Reviewed by Oliver Hunt.
+
 2012-09-06  Michael Saboff  <msaboff@apple.com>
 
         16 bit JSRopeString up converts an 8 bit fibers to 16 bits during resolution
         * interpreter/Interpreter.cpp:
         (JSC::Interpreter::privateExecute):
 
+2012-09-05  Geoffrey Garen  <ggaren@apple.com>
+
+        Named functions should not allocate scope objects for their names
+        https://bugs.webkit.org/show_bug.cgi?id=95659
+
+        Reviewed by Oliver Hunt.
+
+        In most cases, we can merge a function expression's name into its symbol
+        table. This reduces memory footprint per closure from three objects
+        (function + activation + name scope) to two (function + activation),
+        speeds up closure allocation, and speeds up recursive calls.
+
+        In the case of a named function expression that contains a non-strict
+        eval, the rules are so bat-poop crazy that I don't know how to model
+        them without an extra object. Since functions now default to not having
+        such an object, this case needs to allocate the object on function
+        entry.
+
+        Therefore, this patch makes the slow case a bit slower so the fast case
+        can be faster and more memory-efficient. (Note that the slow case already
+        allocates an activation on entry, and until recently also allocated a
+        scope chain node on entry, so adding one allocation on entry shouldn't
+        break the bank.)
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::CodeBlock): Caught a missed initializer. No behavior change.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator): Put the callee in static scope
+        during compilation so it doesn't need to be in dynamic scope at runtime.
+
+        (JSC::BytecodeGenerator::resolveCallee):
+        (JSC::BytecodeGenerator::addCallee): Helper functions for either statically
+        resolving the callee or adding a dynamic scope that will resolve to it,
+        depending on whether you're in the fast path.
+
+        We move the callee into a var location if it's captured because activations
+        prefer to have contiguous ranges of captured variables.
+
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::registerFor):
+        (BytecodeGenerator):
+
+        * dfg/DFGOperations.cpp:
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::privateExecute):
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL): This is the point of the patch: remove
+        one allocation in the case of a named function expression.
+
+        * parser/Parser.cpp:
+        (JSC::::Parser):
+        * parser/Parser.h:
+        (JSC::Scope::declareCallee):
+        (Scope):
+        (Parser):
+        (JSC::parse):
+        * runtime/Executable.cpp:
+        (JSC::EvalExecutable::compileInternal):
+        (JSC::ProgramExecutable::checkSyntax):
+        (JSC::ProgramExecutable::compileInternal):
+        (JSC::FunctionExecutable::produceCodeBlockFor):
+        (JSC::FunctionExecutable::fromGlobalCode): Pipe the callee's name through
+        the parser so we get accurate information on whether the callee was captured.
+
+        (JSC::FunctionExecutable::FunctionExecutable):
+        (JSC::EvalExecutable::compileInternal):
+        (JSC::ProgramExecutable::checkSyntax):
+        (JSC::ProgramExecutable::compileInternal):
+        (JSC::FunctionExecutable::produceCodeBlockFor):
+        (JSC::FunctionExecutable::fromGlobalCode):
+        * runtime/Executable.h:
+        (JSC::FunctionExecutable::create):
+        (FunctionExecutable):
+        (JSC::FunctionExecutable::finishCreation): I had to refactor function
+        creation to support the following function constructor quirk: the function
+        gets a name, but its name is not in lexical scope.
+
+        To simplify this, FunctionExecutable now automatically extracts all the
+        data it needs from the parsed node. The special "fromGlobalCode" path
+        used by the function constructor creates an anonymous function, and then
+        quirkily sets the value used by the .name property to be non-null, even
+        though the parsed name is null.
+
+        * runtime/JSNameScope.h:
+        (JSC::JSNameScope::create):
+        (JSC::JSNameScope::JSNameScope): Added support for explicitly specifying
+        your container scope. The compiler uses this for named function expressions.
+
 2012-09-05  Gavin Barraclough  <barraclough@apple.com>
 
         a = data[a]++; sets the wrong key in data
index 559b0ae..41b23ae 100644 (file)
@@ -1752,6 +1752,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlo
     , m_heap(&m_globalObject->globalData().heap)
     , m_numCalleeRegisters(0)
     , m_numVars(0)
+    , m_numCapturedVars(0)
     , m_isConstructor(isConstructor)
     , m_numParameters(0)
     , m_ownerExecutable(globalObject->globalData(), ownerExecutable, ownerExecutable)
index 6cc25ce..d6c3400 100644 (file)
 
 #include "BatchedTransitionOptimizer.h"
 #include "Comment.h"
+#include "Interpreter.h"
 #include "JSActivation.h"
 #include "JSFunction.h"
-#include "Interpreter.h"
+#include "JSNameScope.h"
 #include "LowLevelInterpreter.h"
-
 #include "StrongInlines.h"
 #include <wtf/text/WTFString.h>
 
@@ -324,7 +324,7 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, JSScope* scope, S
         bool propertyDidExist = 
             globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties.
         
-        JSValue value = JSFunction::create(exec, makeFunction(exec, function), scope);
+        JSValue value = JSFunction::create(exec, FunctionExecutable::create(*m_globalData, function), scope);
         int index = addGlobalVar(
             function->ident(), IsVariable,
             !propertyDidExist ? IsFunctionToSpecialize : NotFunctionOrNotSpecializable);
@@ -419,6 +419,8 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* sc
         }
     }
 
+    RegisterID* calleeRegister = resolveCallee(functionBody); // May push to the scope chain and/or add a captured var.
+
     const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack();
     const DeclarationStacks::VarStack& varStack = functionBody->varStack();
 
@@ -456,6 +458,7 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* sc
     }
 
     codeBlock->m_numCapturedVars = codeBlock->m_numVars;
+
     m_firstLazyFunction = codeBlock->m_numVars;
     for (size_t i = 0; i < functionStack.size(); ++i) {
         FunctionBodyNode* function = functionStack[i];
@@ -497,6 +500,9 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* sc
 
     preserveLastVar();
 
+    // We declare the callee's name last because it should lose to a var, function, and/or parameter declaration.
+    addCallee(functionBody, calleeRegister);
+
     if (isConstructor()) {
         prependComment("'this' because we are a Constructor function");
         emitOpcode(op_create_this);
@@ -549,7 +555,7 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, JSScope* scope, SymbolT
 
     const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack();
     for (size_t i = 0; i < functionStack.size(); ++i)
-        m_codeBlock->addFunctionDecl(makeFunction(m_globalData, functionStack[i]));
+        m_codeBlock->addFunctionDecl(FunctionExecutable::create(*m_globalData, functionStack[i]));
 
     const DeclarationStacks::VarStack& varStack = evalNode->varStack();
     unsigned numVariables = varStack.size();
@@ -574,6 +580,53 @@ RegisterID* BytecodeGenerator::emitInitLazyRegister(RegisterID* reg)
     return reg;
 }
 
+RegisterID* BytecodeGenerator::resolveCallee(FunctionBodyNode* functionBodyNode)
+{
+    if (functionBodyNode->ident().isNull() || !functionBodyNode->functionNameIsInScope())
+        return 0;
+
+    m_calleeRegister.setIndex(RegisterFile::Callee);
+
+    // If non-strict eval is in play, we use a separate object in the scope chain for the callee's name.
+    if ((m_codeBlock->usesEval() && !m_codeBlock->isStrictMode()) || m_shouldEmitDebugHooks) {
+        emitOpcode(op_push_name_scope);
+        instructions().append(addConstant(functionBodyNode->ident()));
+        instructions().append(m_calleeRegister.index());
+        instructions().append(ReadOnly | DontDelete);
+
+        // Put a mirror object in compilation scope, so compile-time variable resolution sees the property name we'll see at runtime.
+        m_scope.set(*globalData(),
+            JSNameScope::create(
+                m_scope->globalObject()->globalExec(),
+                functionBodyNode->ident(),
+                jsUndefined(),
+                ReadOnly | DontDelete,
+                m_scope.get()
+            )
+        );
+        return 0;
+    }
+
+    if (!functionBodyNode->captures(functionBodyNode->ident()))
+        return &m_calleeRegister;
+
+    // Move the callee into the captured section of the stack.
+    return emitMove(addVar(), &m_calleeRegister);
+}
+
+void BytecodeGenerator::addCallee(FunctionBodyNode* functionBodyNode, RegisterID* calleeRegister)
+{
+    if (functionBodyNode->ident().isNull() || !functionBodyNode->functionNameIsInScope())
+        return;
+
+    // If non-strict eval is in play, we use a separate object in the scope chain for the callee's name.
+    if ((m_codeBlock->usesEval() && !m_codeBlock->isStrictMode()) || m_shouldEmitDebugHooks)
+        return;
+
+    ASSERT(calleeRegister);
+    symbolTable().add(functionBodyNode->ident().impl(), SymbolTableEntry(calleeRegister->index(), ReadOnly));
+}
+
 void BytecodeGenerator::addParameter(const Identifier& ident, int parameterIndex)
 {
     // Parameters overwrite var declarations, but not function declarations.
@@ -1830,14 +1883,14 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen
 
 RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function)
 {
-    return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)), false);
+    return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(FunctionExecutable::create(*m_globalData, function)), false);
 }
 
 RegisterID* BytecodeGenerator::emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* function)
 {
     FunctionOffsetMap::AddResult ptr = m_functionOffsets.add(function, 0);
     if (ptr.isNewEntry)
-        ptr.iterator->second = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function));
+        ptr.iterator->second = m_codeBlock->addFunctionDecl(FunctionExecutable::create(*m_globalData, function));
     return emitNewFunctionInternal(dst, ptr.iterator->second, true);
 }
 
@@ -1862,7 +1915,7 @@ RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
 RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
 {
     FunctionBodyNode* function = n->body();
-    unsigned index = m_codeBlock->addFunctionExpr(makeFunction(m_globalData, function));
+    unsigned index = m_codeBlock->addFunctionExpr(FunctionExecutable::create(*m_globalData, function));
     
     createActivationIfNecessary();
     emitOpcode(op_new_func_exp);
@@ -2599,7 +2652,7 @@ void BytecodeGenerator::emitReadOnlyExceptionIfNeeded()
     if (!isStrictMode())
         return;
 
-    RefPtr<RegisterID> error = emitLoad(newTemporary(), createTypeError(scope()->globalObject()->globalExec(), StrictModeReadonlyPropertyWriteError));
+    RefPtr<RegisterID> error = emitLoad(newTemporary(), JSValue(createTypeError(scope()->globalObject()->globalExec(), StrictModeReadonlyPropertyWriteError)));
     emitThrow(error.get());
 }
 
index d3b5266..037a2ce 100644 (file)
@@ -617,7 +617,9 @@ namespace JSC {
         int addGlobalVar(const Identifier&, ConstantMode, FunctionMode);
 
         void addParameter(const Identifier&, int parameterIndex);
-        
+        RegisterID* resolveCallee(FunctionBodyNode*);
+        void addCallee(FunctionBodyNode*, RegisterID*);
+
         void preserveLastVar();
         bool shouldAvoidResolveGlobal();
 
@@ -626,6 +628,9 @@ namespace JSC {
             if (index >= 0)
                 return m_calleeRegisters[index];
 
+            if (index == RegisterFile::Callee)
+                return m_calleeRegister;
+
             ASSERT(m_parameters.size());
             return m_parameters[index + m_parameters.size() + RegisterFile::CallFrameHeaderSize];
         }
@@ -636,16 +641,6 @@ namespace JSC {
 
         unsigned addConstantBuffer(unsigned length);
         
-        FunctionExecutable* makeFunction(ExecState* exec, FunctionBodyNode* body)
-        {
-            return FunctionExecutable::create(exec, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
-        }
-
-        FunctionExecutable* makeFunction(JSGlobalData* globalData, FunctionBodyNode* body)
-        {
-            return FunctionExecutable::create(*globalData, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
-        }
-
         JSString* addStringConstant(const Identifier&);
 
         void addLineInfo(unsigned lineNo)
@@ -716,6 +711,7 @@ namespace JSC {
         HashSet<RefPtr<StringImpl>, IdentifierRepHash> m_functions;
         RegisterID m_ignoredResultRegister;
         RegisterID m_thisRegister;
+        RegisterID m_calleeRegister;
         RegisterID* m_activationRegister;
         SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
         SegmentedVector<RegisterID, 32> m_calleeRegisters;
index 72fe983..824a0a3 100644 (file)
@@ -1243,7 +1243,7 @@ JSCell* DFG_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExec
     ASSERT(functionExecutable->inherits(&FunctionExecutable::s_info));
     JSGlobalData& globalData = exec->globalData();
     NativeCallFrameTracer tracer(&globalData, exec);
-    return static_cast<FunctionExecutable*>(functionExecutable)->make(exec, exec->scope());
+    return JSFunction::create(exec, static_cast<FunctionExecutable*>(functionExecutable), exec->scope());
 }
 
 JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState* exec, JSCell* functionExecutableAsCell)
@@ -1251,14 +1251,7 @@ JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState* exec, JSCell* fu
     ASSERT(functionExecutableAsCell->inherits(&FunctionExecutable::s_info));
     FunctionExecutable* functionExecutable =
         static_cast<FunctionExecutable*>(functionExecutableAsCell);
-    JSFunction* function = functionExecutable->make(exec, exec->scope());
-    if (!functionExecutable->name().isNull()) {
-        JSNameScope* functionScopeObject =
-            JSNameScope::create(
-                exec, functionExecutable->name(), function, ReadOnly | DontDelete);
-        function->setScope(exec->globalData(), functionScopeObject);
-    }
-    return function;
+    return JSFunction::create(exec, functionExecutable, exec->scope());
 }
 
 size_t DFG_OPERATION operationIsObject(ExecState* exec, EncodedJSValue value)
index 37c1cab..3a76380 100644 (file)
@@ -1347,7 +1347,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
         for (int i = 0; i < numFunctions; ++i) {
             FunctionExecutable* function = codeBlock->functionDecl(i);
             PutPropertySlot slot;
-            variableObject->methodTable()->put(variableObject, callFrame, function->name(), function->make(callFrame, scope), slot);
+            variableObject->methodTable()->put(variableObject, callFrame, function->name(), JSFunction::create(callFrame, function, scope), slot);
         }
     }
 
@@ -4279,18 +4279,6 @@ skip_id_custom_self:
         FunctionExecutable* function = codeBlock->functionExpr(funcIndex);
         JSFunction* func = JSFunction::create(callFrame, function, callFrame->scope());
 
-        /* 
-            The Identifier in a FunctionExpression can be referenced from inside
-            the FunctionExpression's FunctionBody to allow the function to call
-            itself recursively. However, unlike in a FunctionDeclaration, the
-            Identifier in a FunctionExpression cannot be referenced from and
-            does not affect the scope enclosing the FunctionExpression.
-         */
-        if (!function->name().isNull()) {
-            JSNameScope* functionScopeObject = JSNameScope::create(callFrame, function->name(), func, ReadOnly | DontDelete);
-            func->setScope(*globalData, functionScopeObject);
-        }
-
         callFrame->uncheckedR(dst) = JSValue(func);
 
         vPC += OPCODE_LENGTH(op_new_func_exp);
index 576dba6..1c65d70 100644 (file)
@@ -2141,7 +2141,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_func)
     STUB_INIT_STACK_FRAME(stackFrame);
     
     ASSERT(stackFrame.callFrame->codeBlock()->codeType() != FunctionCode || !stackFrame.callFrame->codeBlock()->needsFullScopeChain() || stackFrame.callFrame->uncheckedR(stackFrame.callFrame->codeBlock()->activationRegister()).jsValue());
-    return stackFrame.args[0].function()->make(stackFrame.callFrame, stackFrame.callFrame->scope());
+    return JSFunction::create(stackFrame.callFrame, stackFrame.args[0].function(), stackFrame.callFrame->scope());
 }
 
 inline void* jitCompileFor(CallFrame* callFrame, CodeSpecializationKind kind)
@@ -2982,21 +2982,9 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_func_exp)
     CallFrame* callFrame = stackFrame.callFrame;
 
     FunctionExecutable* function = stackFrame.args[0].function();
-    JSFunction* func = function->make(callFrame, callFrame->scope());
+    JSFunction* func = JSFunction::create(callFrame, function, callFrame->scope());
     ASSERT(callFrame->codeBlock()->codeType() != FunctionCode || !callFrame->codeBlock()->needsFullScopeChain() || callFrame->uncheckedR(callFrame->codeBlock()->activationRegister()).jsValue());
 
-    /* 
-        The Identifier in a FunctionExpression can be referenced from inside
-        the FunctionExpression's FunctionBody to allow the function to call
-        itself recursively. However, unlike in a FunctionDeclaration, the
-        Identifier in a FunctionExpression cannot be referenced from and
-        does not affect the scope enclosing the FunctionExpression.
-     */
-    if (!function->name().isNull()) {
-        JSNameScope* functionScopeObject = JSNameScope::create(callFrame, function->name(), func, ReadOnly | DontDelete);
-        func->setScope(callFrame->globalData(), functionScopeObject);
-    }
-
     return func;
 }
 
index c5fff77..820079c 100644 (file)
@@ -1260,7 +1260,7 @@ LLINT_SLOW_PATH_DECL(slow_path_new_func)
 #if LLINT_SLOW_PATH_TRACING
     dataLog("Creating function!\n");
 #endif
-    LLINT_RETURN(codeBlock->functionDecl(pc[2].u.operand)->make(exec, exec->scope()));
+    LLINT_RETURN(JSFunction::create(exec, codeBlock->functionDecl(pc[2].u.operand), exec->scope()));
 }
 
 LLINT_SLOW_PATH_DECL(slow_path_new_func_exp)
@@ -1268,12 +1268,7 @@ LLINT_SLOW_PATH_DECL(slow_path_new_func_exp)
     LLINT_BEGIN();
     CodeBlock* codeBlock = exec->codeBlock();
     FunctionExecutable* function = codeBlock->functionExpr(pc[2].u.operand);
-    JSFunction* func = function->make(exec, exec->scope());
-    
-    if (!function->name().isNull()) {
-        JSNameScope* functionScopeObject = JSNameScope::create(exec, function->name(), func, ReadOnly | DontDelete);
-        func->setScope(globalData, functionScopeObject);
-    }
+    JSFunction* func = JSFunction::create(exec, function, exec->scope());
     
     LLINT_RETURN(func);
 }
index 9fb9e9b..1678bf7 100644 (file)
@@ -749,14 +749,14 @@ namespace JSC {
         : ExpressionNode(location)
         , m_body(body)
     {
-        m_body->finishParsing(source, parameter, ident);
+        m_body->finishParsing(source, parameter, ident, FunctionNameIsInScope);
     }
 
     inline FuncDeclNode::FuncDeclNode(const JSTokenLocation& location, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter)
         : StatementNode(location)
         , m_body(body)
     {
-        m_body->finishParsing(source, parameter, ident);
+        m_body->finishParsing(source, parameter, ident, FunctionNameIsNotInScope);
     }
 
     inline CaseClauseNode::CaseClauseNode(ExpressionNode* expr, SourceElements* statements)
index c057517..14ee838 100644 (file)
@@ -167,17 +167,18 @@ inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, const JSToke
 {
 }
 
-void FunctionBodyNode::finishParsing(const SourceCode& source, ParameterNode* firstParameter, const Identifier& ident)
+void FunctionBodyNode::finishParsing(const SourceCode& source, ParameterNode* firstParameter, const Identifier& ident, FunctionNameIsInScopeToggle functionNameIsInScopeToggle)
 {
     setSource(source);
-    finishParsing(FunctionParameters::create(firstParameter), ident);
+    finishParsing(FunctionParameters::create(firstParameter), ident, functionNameIsInScopeToggle);
 }
 
-void FunctionBodyNode::finishParsing(PassRefPtr<FunctionParameters> parameters, const Identifier& ident)
+void FunctionBodyNode::finishParsing(PassRefPtr<FunctionParameters> parameters, const Identifier& ident, FunctionNameIsInScopeToggle functionNameIsInScopeToggle)
 {
     ASSERT(!source().isNull());
     m_parameters = parameters;
     m_ident = ident;
+    m_functionNameIsInScopeToggle = functionNameIsInScopeToggle;
 }
 
 FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, const JSTokenLocation& location, bool inStrictContext)
index 8e48055..475689c 100644 (file)
@@ -1403,6 +1403,7 @@ namespace JSC {
         FunctionParameters(ParameterNode*);
     };
 
+    enum FunctionNameIsInScopeToggle { FunctionNameIsNotInScope, FunctionNameIsInScope };
     class FunctionBodyNode : public ScopeNode {
     public:
         static const bool isFunctionNode = true;
@@ -1414,13 +1415,16 @@ namespace JSC {
 
         virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
 
-        void finishParsing(const SourceCode&, ParameterNode*, const Identifier&);
-        void finishParsing(PassRefPtr<FunctionParameters>, const Identifier&);
+        void finishParsing(const SourceCode&, ParameterNode*, const Identifier&, FunctionNameIsInScopeToggle);
+        void finishParsing(PassRefPtr<FunctionParameters>, const Identifier&, FunctionNameIsInScopeToggle);
         
         const Identifier& ident() { return m_ident; }
         void setInferredName(const Identifier& inferredName) { ASSERT(!inferredName.isNull()); m_inferredName = inferredName; }
         const Identifier& inferredName() { return m_inferredName.isEmpty() ? m_ident : m_inferredName; }
 
+        bool functionNameIsInScope() { return m_functionNameIsInScopeToggle == FunctionNameIsInScope; }
+        FunctionNameIsInScopeToggle functionNameIsInScopeToggle() { return m_functionNameIsInScopeToggle; }
+
         static const bool scopeIsFunction = true;
 
     private:
@@ -1429,6 +1433,7 @@ namespace JSC {
 
         Identifier m_ident;
         Identifier m_inferredName;
+        FunctionNameIsInScopeToggle m_functionNameIsInScopeToggle;
         RefPtr<FunctionParameters> m_parameters;
     };
 
index fdda73c..a70c684 100644 (file)
@@ -40,7 +40,7 @@ using namespace std;
 namespace JSC {
 
 template <typename LexerType>
-Parser<LexerType>::Parser(JSGlobalData* globalData, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode)
+Parser<LexerType>::Parser(JSGlobalData* globalData, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode)
     : m_globalData(globalData)
     , m_source(&source)
     , m_stack(wtfThreadData().stack())
@@ -71,6 +71,8 @@ Parser<LexerType>::Parser(JSGlobalData* globalData, const SourceCode& source, Fu
         for (unsigned i = 0; i < parameters->size(); i++)
             scope->declareParameter(&parameters->at(i));
     }
+    if (!name.isNull())
+        scope->declareCallee(&name);
     next();
     m_lexer->setLastLineNumber(tokenLine());
 }
index 401f21e..3ca5ec4 100644 (file)
@@ -208,6 +208,11 @@ struct Scope {
     bool isFunction() { return m_isFunction; }
     bool isFunctionBoundary() { return m_isFunctionBoundary; }
 
+    void declareCallee(const Identifier* ident)
+    {
+        m_declaredVariables.add(ident->ustring().impl());
+    }
+
     bool declareVariable(const Identifier* ident)
     {
         bool isValidStrictMode = m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
@@ -382,7 +387,7 @@ class Parser {
     WTF_MAKE_FAST_ALLOCATED;
 
 public:
-    Parser(JSGlobalData*, const SourceCode&, FunctionParameters*, JSParserStrictness, JSParserMode);
+    Parser(JSGlobalData*, const SourceCode&, FunctionParameters*, const Identifier&, JSParserStrictness, JSParserMode);
     ~Parser();
 
     template <class ParsedNode>
@@ -1020,17 +1025,17 @@ PassRefPtr<ParsedNode> Parser<LexerType>::parse(JSGlobalObject* lexicalGlobalObj
 }
 
 template <class ParsedNode>
-PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, Debugger* debugger, ExecState* execState, JSObject** exception)
+PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode, Debugger* debugger, ExecState* execState, JSObject** exception)
 {
     SamplingRegion samplingRegion("Parsing");
 
     ASSERT(source.provider()->data());
 
     if (source.provider()->data()->is8Bit()) {
-        Parser< Lexer<LChar> > parser(globalData, source, parameters, strictness, parserMode);
+        Parser< Lexer<LChar> > parser(globalData, source, parameters, name, strictness, parserMode);
         return parser.parse<ParsedNode>(lexicalGlobalObject, debugger, execState, exception);
     }
-    Parser< Lexer<UChar> > parser(globalData, source, parameters, strictness, parserMode);
+    Parser< Lexer<UChar> > parser(globalData, source, parameters, name, strictness, parserMode);
     return parser.parse<ParsedNode>(lexicalGlobalObject, debugger, execState, exception);
 }
 
index 77c2749..5d27397 100644 (file)
@@ -133,24 +133,17 @@ void ProgramExecutable::destroy(JSCell* cell)
 
 const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) };
 
-FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext)
-    : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, source, inStrictContext)
+FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, FunctionBodyNode* node)
+    : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, node->source(), node->isStrictMode())
     , m_numCapturedVariables(0)
-    , m_forceUsesArguments(forceUsesArguments)
-    , m_parameters(parameters)
-    , m_name(name)
-    , m_inferredName(inferredName.isNull() ? globalData.propertyNames->emptyIdentifier : inferredName)
-{
-}
-
-FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext)
-    : ScriptExecutable(exec->globalData().functionExecutableStructure.get(), exec, source, inStrictContext)
-    , m_numCapturedVariables(0)
-    , m_forceUsesArguments(forceUsesArguments)
-    , m_parameters(parameters)
-    , m_name(name)
-    , m_inferredName(inferredName.isNull() ? exec->globalData().propertyNames->emptyIdentifier : inferredName)
+    , m_forceUsesArguments(node->usesArguments())
+    , m_parameters(node->parameters())
+    , m_name(node->ident())
+    , m_inferredName(node->inferredName().isNull() ? globalData.propertyNames->emptyIdentifier : node->inferredName())
+    , m_functionNameIsInScopeToggle(node->functionNameIsInScopeToggle())
 {
+    m_firstLine = node->lineNo();
+    m_lastLine = node->lastLine();
 }
 
 void FunctionExecutable::destroy(JSCell* cell)
@@ -210,7 +203,7 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCo
     } else {
         if (!lexicalGlobalObject->evalEnabled())
             return throwError(exec, createEvalError(exec, ASCIILiteral("Eval is disabled")));
-        RefPtr<EvalNode> evalNode = parse<EvalNode>(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, EvalNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
+        RefPtr<EvalNode> evalNode = parse<EvalNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), isStrictMode() ? JSParseStrict : JSParseNormal, EvalNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
         if (!evalNode) {
             ASSERT(exception);
             return exception;
@@ -293,7 +286,7 @@ JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
     JSObject* exception = 0;
     JSGlobalData* globalData = &exec->globalData();
     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
-    RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
+    RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
     if (programNode)
         return 0;
     ASSERT(exception);
@@ -335,7 +328,7 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, JSScope* scope, JI
         newCodeBlock->setAlternative(static_pointer_cast<CodeBlock>(m_programCodeBlock.release()));
         m_programCodeBlock = newCodeBlock.release();
     } else {
-        RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
+        RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), isStrictMode() ? JSParseStrict : JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
         if (!programNode) {
             ASSERT(exception);
             return exception;
@@ -478,7 +471,18 @@ PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(JSScope* s
     exception = 0;
     JSGlobalData* globalData = scope->globalData();
     JSGlobalObject* globalObject = scope->globalObject();
-    RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(globalData, globalObject, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, FunctionBodyNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, 0, 0, &exception);
+    RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(
+        globalData,
+        globalObject,
+        m_source,
+        m_parameters.get(),
+        name(),
+        isStrictMode() ? JSParseStrict : JSParseNormal,
+        FunctionBodyNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode,
+        0,
+        0,
+        &exception
+    );
 
     if (!body) {
         ASSERT(exception);
@@ -486,7 +490,7 @@ PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(JSScope* s
     }
     if (m_forceUsesArguments)
         body->setUsesArguments();
-    body->finishParsing(m_parameters, m_name);
+    body->finishParsing(m_parameters, m_name, m_functionNameIsInScopeToggle);
     recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
 
     OwnPtr<FunctionCodeBlock> result;
@@ -647,16 +651,16 @@ void FunctionExecutable::unlinkCalls()
 #endif
 }
 
-FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
+FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
 {
     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
-    RefPtr<ProgramNode> program = parse<ProgramNode>(&exec->globalData(), lexicalGlobalObject, source, 0, JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, debugger, exec, exception);
+    RefPtr<ProgramNode> program = parse<ProgramNode>(&exec->globalData(), lexicalGlobalObject, source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, debugger, exec, exception);
     if (!program) {
         ASSERT(*exception);
         return 0;
     }
 
-    // Uses of this function that would not result in a single function expression are invalid.
+    // This function assumes an input string that would result in a single anonymous function expression.
     StatementNode* exprStatement = program->singleStatement();
     ASSERT(exprStatement);
     ASSERT(exprStatement->isExprStatement());
@@ -665,8 +669,11 @@ FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functio
     ASSERT(funcExpr->isFuncExprNode());
     FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body();
     ASSERT(body);
+    ASSERT(body->ident().isNull());
 
-    return FunctionExecutable::create(exec->globalData(), functionName, functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
+    FunctionExecutable* functionExecutable = FunctionExecutable::create(exec->globalData(), body);
+    functionExecutable->m_nameValue.set(exec->globalData(), functionExecutable, jsString(&exec->globalData(), name.ustring()));
+    return functionExecutable;
 }
 
 String FunctionExecutable::paramString() const
index 6c7bb42..4947df6 100644 (file)
@@ -539,27 +539,16 @@ namespace JSC {
     public:
         typedef ScriptExecutable Base;
 
-        static FunctionExecutable* create(ExecState* exec, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
+        static FunctionExecutable* create(JSGlobalData& globalData, FunctionBodyNode* node)
         {
-            FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
-            executable->finishCreation(exec->globalData(), name, firstLine, lastLine);
-            return executable;
-        }
-
-        static FunctionExecutable* create(JSGlobalData& globalData, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
-        {
-            FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
-            executable->finishCreation(globalData, name, firstLine, lastLine);
+            FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, node);
+            executable->finishCreation(globalData);
             return executable;
         }
+        static FunctionExecutable* fromGlobalCode(const Identifier& name, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
 
         static void destroy(JSCell*);
 
-        JSFunction* make(ExecState* exec, JSScope* scope)
-        {
-            return JSFunction::create(exec, this, scope);
-        }
-        
         // Returns either call or construct bytecode. This can be appropriate
         // for answering questions that that don't vary between call and construct --
         // for example, argumentsRegister().
@@ -708,7 +697,6 @@ namespace JSC {
 
         void clearCodeIfNotCompiling();
         static void visitChildren(JSCell*, SlotVisitor&);
-        static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
         static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
         {
             return Structure::create(globalData, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), &s_info);
@@ -721,17 +709,14 @@ namespace JSC {
         void clearCode();
 
     protected:
-        void finishCreation(JSGlobalData& globalData, const Identifier& name, int firstLine, int lastLine)
+        void finishCreation(JSGlobalData& globalData)
         {
             Base::finishCreation(globalData);
-            m_firstLine = firstLine;
-            m_lastLine = lastLine;
-            m_nameValue.set(globalData, this, jsString(&globalData, name.ustring()));
+            m_nameValue.set(globalData, this, jsString(&globalData, name().ustring()));
         }
 
     private:
-        FunctionExecutable(JSGlobalData&, const Identifier& name, const Identifier& inferredName, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool);
-        FunctionExecutable(ExecState*, const Identifier& name, const Identifier& inferredName, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool);
+        FunctionExecutable(JSGlobalData&, FunctionBodyNode*);
 
         JSObject* compileForCallInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX);
         JSObject* compileForConstructInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX);
@@ -764,6 +749,7 @@ namespace JSC {
         OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct;
         Identifier m_name;
         Identifier m_inferredName;
+        FunctionNameIsInScopeToggle m_functionNameIsInScopeToggle;
         WriteBarrier<JSString> m_nameValue;
         WriteBarrier<SharedSymbolTable> m_symbolTable;
     };
index 73b1208..e67370d 100644 (file)
@@ -38,7 +38,14 @@ public:
 
     static JSNameScope* create(ExecState* exec, const Identifier& identifier, JSValue value, unsigned attributes)
     {
-        JSNameScope* scopeObject = new (NotNull, allocateCell<JSNameScope>(*exec->heap())) JSNameScope(exec);
+        JSNameScope* scopeObject = new (NotNull, allocateCell<JSNameScope>(*exec->heap())) JSNameScope(exec, exec->scope());
+        scopeObject->finishCreation(exec, identifier, value, attributes);
+        return scopeObject;
+    }
+
+    static JSNameScope* create(ExecState* exec, const Identifier& identifier, JSValue value, unsigned attributes, JSScope* next)
+    {
+        JSNameScope* scopeObject = new (NotNull, allocateCell<JSNameScope>(*exec->heap())) JSNameScope(exec, next);
         scopeObject->finishCreation(exec, identifier, value, attributes);
         return scopeObject;
     }
@@ -64,12 +71,12 @@ protected:
     static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | Base::StructureFlags;
 
 private:
-    JSNameScope(ExecState* exec)
+    JSNameScope(ExecState* exec, JSScope* next)
         : Base(
             exec->globalData(),
             exec->lexicalGlobalObject()->nameScopeStructure(),
             reinterpret_cast<Register*>(&m_registerStore + 1),
-            exec->scope()
+            next
         )
     {
     }