Changeset 127698 in webkit


Ignore:
Timestamp:
Sep 5, 2012 11:17:59 PM (12 years ago)
Author:
ggaren@apple.com
Message:

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

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

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.

LayoutTests:

Added coverage for some extra-tricky cases.

  • fast/js/named-function-expression-expected.txt:
  • fast/js/script-tests/named-function-expression.js:

(shouldBeTrueWithDescription): I rolled my own shouldBeTrue() here to avoid the
built-in shouldBe()'s eval scoping, which can change the variable
resolution rules I'm trying to test.

  • inspector/debugger/debugger-expand-scope-expected.txt: Not sure why this

result used to miss the function name scope, but the new result is a
progression, so I've updated the expected results.

Location:
trunk
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r127697 r127698  
     12012-09-03  Geoffrey Garen  <ggaren@apple.com>
     2
     3        Named functions should not allocate scope objects for their names
     4        https://bugs.webkit.org/show_bug.cgi?id=95659
     5
     6        Reviewed by Oliver Hunt.
     7
     8        Added coverage for some extra-tricky cases.
     9
     10        * fast/js/named-function-expression-expected.txt:
     11        * fast/js/script-tests/named-function-expression.js:
     12        (shouldBeTrueWithDescription): I rolled my own shouldBeTrue() here to avoid the
     13        built-in shouldBe()'s eval scoping, which can change the variable
     14        resolution rules I'm trying to test.
     15
     16        * inspector/debugger/debugger-expand-scope-expected.txt: Not sure why this
     17        result used to miss the function name scope, but the new result is a
     18        progression, so I've updated the expected results.
     19
    1202012-09-05  Csaba Osztrogonác  <ossy@webkit.org>
    221
  • trunk/LayoutTests/fast/js/named-function-expression-expected.txt

    r75408 r127698  
    1 Bug 4698 - kjs does not allow named functions in function expressions.
     1Tests variable resolution rules for named function expressions.
    22
    33On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
     
    1818regression test where kjs regarded an anonymous function declaration (which is illegal) as a FunctionExpr
    1919PASS var hadError = 0; try { eval("function(){ return 2; };"); } catch(e) { hadError = 1; }; hadError; is 1
     20
     21-----
     22
     23PASS: (function closure() { return closure == arguments.callee && !this.closure; })() should be true and is.
     24PASS: (function closure() { closure = 1; return closure == arguments.callee && !this.closure; })() should be true and is.
     25PASS: (function closure(closure) { return closure == 1 && !this.closure; })(1) should be true and is.
     26PASS: (function closure() { var closure = 1; return closure == 1 && !this.closure; })() should be true and is.
     27PASS: (function closure() { function closure() { }; return closure != arguments.callee && !this.closure; })() should be true and is.
     28PASS: (function closure() { return (function() { return closure && !this.closure; })(); })() should be true and is.
     29PASS: (function closure() { return (function() { closure = null; return closure && !this.closure; })(); })() should be true and is.
     30PASS: (function closure() { return (function() { return closure && !this.closure; }); })()() should be true and is.
     31PASS: (function closure() { return (function() { closure = null; return closure && !this.closure; }); })()() should be true and is.
     32PASS: (function closure() { eval("var closure"); return closure == undefined && !this.closure; })() should be true and is.
     33PASS: (function closure() { eval("function closure() { }"); return closure != arguments.callee && !this.closure; })() should be true and is.
     34PASS: (function closure() { eval("var closure;"); closure = 1; return closure == 1 && !this.closure; })() should be true and is.
     35PASS: (function closure() { eval("var closure"); delete closure; return closure == arguments.callee && !this.closure; })() should be true and is.
     36PASS: (function closure() { eval("function closure() { }"); delete closure; return closure == arguments.callee && !this.closure; })() should be true and is.
     37PASS: (function closure() { eval("closure = 1;"); return closure == arguments.callee && !this.closure; })() should be true and is.
    2038PASS successfullyParsed is true
    2139
  • trunk/LayoutTests/fast/js/script-tests/named-function-expression.js

    r98407 r127698  
    11description(
    2 "Bug 4698 - kjs does not allow named functions in function expressions."
     2"Tests variable resolution rules for named function expressions."
    33);
    44
     
    2525debug("regression test where kjs regarded an anonymous function declaration (which is illegal) as a FunctionExpr");
    2626shouldBe('var hadError = 0; try { eval("function(){ return 2; };"); } catch(e) { hadError = 1; }; hadError;', "1");
     27
     28debug("\n-----\n");
     29
     30function shouldBeTrueWithDescription(x, xDescription)
     31{
     32        if (x) {
     33                debug("PASS: " + xDescription + " should be true and is.");
     34                return;
     35        }
     36
     37        debug("FAIL: " + xDescription + " should be true but isn't.");
     38}
     39
     40// Recursion.
     41shouldBeTrueWithDescription(
     42        (function closure() { return closure == arguments.callee && !this.closure; })(),
     43        "(function closure() { return closure == arguments.callee && !this.closure; })()"
     44);
     45
     46// Assignment.
     47shouldBeTrueWithDescription(
     48        (function closure() { closure = 1; return closure == arguments.callee && !this.closure; })(),
     49        "(function closure() { closure = 1; return closure == arguments.callee && !this.closure; })()"
     50);
     51
     52// Function name vs parameter.
     53shouldBeTrueWithDescription(
     54        (function closure(closure) { return closure == 1 && !this.closure; })(1),
     55        "(function closure(closure) { return closure == 1 && !this.closure; })(1)"
     56);
     57
     58// Function name vs var.
     59shouldBeTrueWithDescription(
     60        (function closure() { var closure = 1; return closure == 1 && !this.closure; })(),
     61        "(function closure() { var closure = 1; return closure == 1 && !this.closure; })()"
     62);
     63
     64// Function name vs declared function.
     65shouldBeTrueWithDescription(
     66        (function closure() { function closure() { }; return closure != arguments.callee && !this.closure; })(),
     67        "(function closure() { function closure() { }; return closure != arguments.callee && !this.closure; })()"
     68);
     69
     70// Resolve before tear-off.
     71shouldBeTrueWithDescription(
     72        (function closure() { return (function() { return closure && !this.closure; })(); })(),
     73        "(function closure() { return (function() { return closure && !this.closure; })(); })()"
     74);
     75
     76// Resolve assignment before tear-off.
     77shouldBeTrueWithDescription(
     78        (function closure() { return (function() { closure = null; return closure && !this.closure; })(); })(),
     79        "(function closure() { return (function() { closure = null; return closure && !this.closure; })(); })()"
     80);
     81
     82// Resolve after tear-off.
     83shouldBeTrueWithDescription(
     84        (function closure() { return (function() { return closure && !this.closure; }); })()(),
     85        "(function closure() { return (function() { return closure && !this.closure; }); })()()"
     86);
     87
     88// Resolve assignment after tear-off.
     89shouldBeTrueWithDescription(
     90        (function closure() { return (function() { closure = null; return closure && !this.closure; }); })()(),
     91        "(function closure() { return (function() { closure = null; return closure && !this.closure; }); })()()"
     92);
     93
     94// Eval var shadowing (should overwrite).
     95shouldBeTrueWithDescription(
     96        (function closure() { eval("var closure"); return closure == undefined && !this.closure; })(),
     97        "(function closure() { eval(\"var closure\"); return closure == undefined && !this.closure; })()"
     98);
     99
     100// Eval function shadowing (should overwrite).
     101shouldBeTrueWithDescription(
     102        (function closure() { eval("function closure() { }"); return closure != arguments.callee && !this.closure; })(),
     103        "(function closure() { eval(\"function closure() { }\"); return closure != arguments.callee && !this.closure; })()"
     104);
     105
     106// Eval shadowing (should overwrite), followed by put (should overwrite).
     107shouldBeTrueWithDescription(
     108        (function closure() { eval("var closure;"); closure = 1; return closure == 1 && !this.closure; })(),
     109        "(function closure() { eval(\"var closure;\"); closure = 1; return closure == 1 && !this.closure; })()"
     110);
     111
     112// Eval var shadowing, followed by delete (should not overwrite).
     113shouldBeTrueWithDescription(
     114        (function closure() { eval("var closure"); delete closure; return closure == arguments.callee && !this.closure; })(),
     115        "(function closure() { eval(\"var closure\"); delete closure; return closure == arguments.callee && !this.closure; })()"
     116);
     117
     118// Eval function shadowing, followed by delete (should not overwrite).
     119shouldBeTrueWithDescription(
     120        (function closure() { eval("function closure() { }"); delete closure; return closure == arguments.callee && !this.closure; })(),
     121        "(function closure() { eval(\"function closure() { }\"); delete closure; return closure == arguments.callee && !this.closure; })()"
     122);
     123
     124// Eval assignment (should not overwrite).
     125shouldBeTrueWithDescription(
     126        (function closure() { eval("closure = 1;"); return closure == arguments.callee && !this.closure; })(),
     127        "(function closure() { eval(\"closure = 1;\"); return closure == arguments.callee && !this.closure; })()"
     128);
  • trunk/LayoutTests/inspector/debugger/debugger-expand-scope-expected.txt

    r118161 r127698  
    2020    makeClosureLocalVar: "local.TextParam"
    2121    n: "TextParam"
     22WindowWith Block
     23    makeClosure: function makeClosure(n) {
    2224WindowGlobal
    2325    <section collapsed>
  • trunk/Source/JavaScriptCore/ChangeLog

    r127676 r127698  
     12012-09-05  Geoffrey Garen  <ggaren@apple.com>
     2
     3        Named functions should not allocate scope objects for their names
     4        https://bugs.webkit.org/show_bug.cgi?id=95659
     5
     6        Reviewed by Oliver Hunt.
     7
     8        In most cases, we can merge a function expression's name into its symbol
     9        table. This reduces memory footprint per closure from three objects
     10        (function + activation + name scope) to two (function + activation),
     11        speeds up closure allocation, and speeds up recursive calls.
     12
     13        In the case of a named function expression that contains a non-strict
     14        eval, the rules are so bat-poop crazy that I don't know how to model
     15        them without an extra object. Since functions now default to not having
     16        such an object, this case needs to allocate the object on function
     17        entry.
     18
     19        Therefore, this patch makes the slow case a bit slower so the fast case
     20        can be faster and more memory-efficient. (Note that the slow case already
     21        allocates an activation on entry, and until recently also allocated a
     22        scope chain node on entry, so adding one allocation on entry shouldn't
     23        break the bank.)
     24
     25        * bytecode/CodeBlock.cpp:
     26        (JSC::CodeBlock::CodeBlock): Caught a missed initializer. No behavior change.
     27
     28        * bytecompiler/BytecodeGenerator.cpp:
     29        (JSC::BytecodeGenerator::BytecodeGenerator): Put the callee in static scope
     30        during compilation so it doesn't need to be in dynamic scope at runtime.
     31
     32        (JSC::BytecodeGenerator::resolveCallee):
     33        (JSC::BytecodeGenerator::addCallee): Helper functions for either statically
     34        resolving the callee or adding a dynamic scope that will resolve to it,
     35        depending on whether you're in the fast path.
     36
     37        We move the callee into a var location if it's captured because activations
     38        prefer to have contiguous ranges of captured variables.
     39
     40        * bytecompiler/BytecodeGenerator.h:
     41        (JSC::BytecodeGenerator::registerFor):
     42        (BytecodeGenerator):
     43
     44        * dfg/DFGOperations.cpp:
     45        * interpreter/Interpreter.cpp:
     46        (JSC::Interpreter::privateExecute):
     47        * jit/JITStubs.cpp:
     48        (JSC::DEFINE_STUB_FUNCTION):
     49        * llint/LLIntSlowPaths.cpp:
     50        (JSC::LLInt::LLINT_SLOW_PATH_DECL): This is the point of the patch: remove
     51        one allocation in the case of a named function expression.
     52
     53        * parser/Parser.cpp:
     54        (JSC::::Parser):
     55        * parser/Parser.h:
     56        (JSC::Scope::declareCallee):
     57        (Scope):
     58        (Parser):
     59        (JSC::parse):
     60        * runtime/Executable.cpp:
     61        (JSC::EvalExecutable::compileInternal):
     62        (JSC::ProgramExecutable::checkSyntax):
     63        (JSC::ProgramExecutable::compileInternal):
     64        (JSC::FunctionExecutable::produceCodeBlockFor):
     65        (JSC::FunctionExecutable::fromGlobalCode): Pipe the callee's name through
     66        the parser so we get accurate information on whether the callee was captured.
     67
     68        (JSC::FunctionExecutable::FunctionExecutable):
     69        (JSC::EvalExecutable::compileInternal):
     70        (JSC::ProgramExecutable::checkSyntax):
     71        (JSC::ProgramExecutable::compileInternal):
     72        (JSC::FunctionExecutable::produceCodeBlockFor):
     73        (JSC::FunctionExecutable::fromGlobalCode):
     74        * runtime/Executable.h:
     75        (JSC::FunctionExecutable::create):
     76        (FunctionExecutable):
     77        (JSC::FunctionExecutable::finishCreation): I had to refactor function
     78        creation to support the following function constructor quirk: the function
     79        gets a name, but its name is not in lexical scope.
     80
     81        To simplify this, FunctionExecutable now automatically extracts all the
     82        data it needs from the parsed node. The special "fromGlobalCode" path
     83        used by the function constructor creates an anonymous function, and then
     84        quirkily sets the value used by the .name property to be non-null, even
     85        though the parsed name is null.
     86
     87        * runtime/JSNameScope.h:
     88        (JSC::JSNameScope::create):
     89        (JSC::JSNameScope::JSNameScope): Added support for explicitly specifying
     90        your container scope. The compiler uses this for named function expressions.
     91
    1922012-09-05  Gavin Barraclough  <barraclough@apple.com>
    293
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r127505 r127698  
    17531753    , m_numCalleeRegisters(0)
    17541754    , m_numVars(0)
     1755    , m_numCapturedVars(0)
    17551756    , m_isConstructor(isConstructor)
    17561757    , m_numParameters(0)
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r127647 r127698  
    3434#include "BatchedTransitionOptimizer.h"
    3535#include "Comment.h"
     36#include "Interpreter.h"
    3637#include "JSActivation.h"
    3738#include "JSFunction.h"
    38 #include "Interpreter.h"
     39#include "JSNameScope.h"
    3940#include "LowLevelInterpreter.h"
    40 
    4141#include "StrongInlines.h"
    4242#include <wtf/text/WTFString.h>
     
    325325            globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties.
    326326       
    327         JSValue value = JSFunction::create(exec, makeFunction(exec, function), scope);
     327        JSValue value = JSFunction::create(exec, FunctionExecutable::create(*m_globalData, function), scope);
    328328        int index = addGlobalVar(
    329329            function->ident(), IsVariable,
     
    420420    }
    421421
     422    RegisterID* calleeRegister = resolveCallee(functionBody); // May push to the scope chain and/or add a captured var.
     423
    422424    const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack();
    423425    const DeclarationStacks::VarStack& varStack = functionBody->varStack();
     
    457459
    458460    codeBlock->m_numCapturedVars = codeBlock->m_numVars;
     461
    459462    m_firstLazyFunction = codeBlock->m_numVars;
    460463    for (size_t i = 0; i < functionStack.size(); ++i) {
     
    497500
    498501    preserveLastVar();
     502
     503    // We declare the callee's name last because it should lose to a var, function, and/or parameter declaration.
     504    addCallee(functionBody, calleeRegister);
    499505
    500506    if (isConstructor()) {
     
    550556    const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack();
    551557    for (size_t i = 0; i < functionStack.size(); ++i)
    552         m_codeBlock->addFunctionDecl(makeFunction(m_globalData, functionStack[i]));
     558        m_codeBlock->addFunctionDecl(FunctionExecutable::create(*m_globalData, functionStack[i]));
    553559
    554560    const DeclarationStacks::VarStack& varStack = evalNode->varStack();
     
    573579    instructions().append(reg->index());
    574580    return reg;
     581}
     582
     583RegisterID* BytecodeGenerator::resolveCallee(FunctionBodyNode* functionBodyNode)
     584{
     585    if (functionBodyNode->ident().isNull())
     586        return 0;
     587
     588    m_calleeRegister.setIndex(RegisterFile::Callee);
     589
     590    // If non-strict eval is in play, we use a separate object in the scope chain for the callee's name.
     591    if ((m_codeBlock->usesEval() && !m_codeBlock->isStrictMode()) || m_shouldEmitDebugHooks) {
     592        emitOpcode(op_push_name_scope);
     593        instructions().append(addConstant(functionBodyNode->ident()));
     594        instructions().append(m_calleeRegister.index());
     595        instructions().append(ReadOnly | DontDelete);
     596
     597        // Put a mirror object in compilation scope, so compile-time variable resolution sees the property name we'll see at runtime.
     598        m_scope.set(*globalData(),
     599            JSNameScope::create(
     600                m_scope->globalObject()->globalExec(),
     601                functionBodyNode->ident(),
     602                jsUndefined(),
     603                ReadOnly | DontDelete,
     604                m_scope.get()
     605            )
     606        );
     607        return 0;
     608    }
     609
     610    if (!functionBodyNode->captures(functionBodyNode->ident()))
     611        return &m_calleeRegister;
     612
     613    // Move the callee into the captured section of the stack.
     614    return emitMove(addVar(), &m_calleeRegister);
     615}
     616
     617void BytecodeGenerator::addCallee(FunctionBodyNode* functionBodyNode, RegisterID* calleeRegister)
     618{
     619    if (functionBodyNode->ident().isNull())
     620        return;
     621
     622    // If non-strict eval is in play, we use a separate object in the scope chain for the callee's name.
     623    if ((m_codeBlock->usesEval() && !m_codeBlock->isStrictMode()) || m_shouldEmitDebugHooks)
     624        return;
     625
     626    ASSERT(calleeRegister);
     627    symbolTable().add(functionBodyNode->ident().impl(), SymbolTableEntry(calleeRegister->index(), ReadOnly));
    575628}
    576629
     
    18311884RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function)
    18321885{
    1833     return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)), false);
     1886    return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(FunctionExecutable::create(*m_globalData, function)), false);
    18341887}
    18351888
     
    18381891    FunctionOffsetMap::AddResult ptr = m_functionOffsets.add(function, 0);
    18391892    if (ptr.isNewEntry)
    1840         ptr.iterator->second = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function));
     1893        ptr.iterator->second = m_codeBlock->addFunctionDecl(FunctionExecutable::create(*m_globalData, function));
    18411894    return emitNewFunctionInternal(dst, ptr.iterator->second, true);
    18421895}
     
    18631916{
    18641917    FunctionBodyNode* function = n->body();
    1865     unsigned index = m_codeBlock->addFunctionExpr(makeFunction(m_globalData, function));
     1918    unsigned index = m_codeBlock->addFunctionExpr(FunctionExecutable::create(*m_globalData, function));
    18661919   
    18671920    createActivationIfNecessary();
     
    26002653        return;
    26012654
    2602     RefPtr<RegisterID> error = emitLoad(newTemporary(), createTypeError(scope()->globalObject()->globalExec(), StrictModeReadonlyPropertyWriteError));
     2655    RefPtr<RegisterID> error = emitLoad(newTemporary(), JSValue(createTypeError(scope()->globalObject()->globalExec(), StrictModeReadonlyPropertyWriteError)));
    26032656    emitThrow(error.get());
    26042657}
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r127647 r127698  
    618618
    619619        void addParameter(const Identifier&, int parameterIndex);
    620        
     620        RegisterID* resolveCallee(FunctionBodyNode*);
     621        void addCallee(FunctionBodyNode*, RegisterID*);
     622
    621623        void preserveLastVar();
    622624        bool shouldAvoidResolveGlobal();
     
    626628            if (index >= 0)
    627629                return m_calleeRegisters[index];
     630
     631            if (index == RegisterFile::Callee)
     632                return m_calleeRegister;
    628633
    629634            ASSERT(m_parameters.size());
     
    637642        unsigned addConstantBuffer(unsigned length);
    638643       
    639         FunctionExecutable* makeFunction(ExecState* exec, FunctionBodyNode* body)
    640         {
    641             return FunctionExecutable::create(exec, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
    642         }
    643 
    644         FunctionExecutable* makeFunction(JSGlobalData* globalData, FunctionBodyNode* body)
    645         {
    646             return FunctionExecutable::create(*globalData, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
    647         }
    648 
    649644        JSString* addStringConstant(const Identifier&);
    650645
     
    717712        RegisterID m_ignoredResultRegister;
    718713        RegisterID m_thisRegister;
     714        RegisterID m_calleeRegister;
    719715        RegisterID* m_activationRegister;
    720716        SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r127536 r127698  
    12441244    JSGlobalData& globalData = exec->globalData();
    12451245    NativeCallFrameTracer tracer(&globalData, exec);
    1246     return static_cast<FunctionExecutable*>(functionExecutable)->make(exec, exec->scope());
     1246    return JSFunction::create(exec, static_cast<FunctionExecutable*>(functionExecutable), exec->scope());
    12471247}
    12481248
     
    12521252    FunctionExecutable* functionExecutable =
    12531253        static_cast<FunctionExecutable*>(functionExecutableAsCell);
    1254     JSFunction* function = functionExecutable->make(exec, exec->scope());
    1255     if (!functionExecutable->name().isNull()) {
    1256         JSNameScope* functionScopeObject =
    1257             JSNameScope::create(
    1258                 exec, functionExecutable->name(), function, ReadOnly | DontDelete);
    1259         function->setScope(exec->globalData(), functionScopeObject);
    1260     }
    1261     return function;
     1254    return JSFunction::create(exec, functionExecutable, exec->scope());
    12621255}
    12631256
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r127505 r127698  
    13481348            FunctionExecutable* function = codeBlock->functionDecl(i);
    13491349            PutPropertySlot slot;
    1350             variableObject->methodTable()->put(variableObject, callFrame, function->name(), function->make(callFrame, scope), slot);
     1350            variableObject->methodTable()->put(variableObject, callFrame, function->name(), JSFunction::create(callFrame, function, scope), slot);
    13511351        }
    13521352    }
     
    42804280        JSFunction* func = function->make(callFrame, callFrame->scope());
    42814281
    4282         /*
    4283             The Identifier in a FunctionExpression can be referenced from inside
    4284             the FunctionExpression's FunctionBody to allow the function to call
    4285             itself recursively. However, unlike in a FunctionDeclaration, the
    4286             Identifier in a FunctionExpression cannot be referenced from and
    4287             does not affect the scope enclosing the FunctionExpression.
    4288          */
    4289         if (!function->name().isNull()) {
    4290             JSNameScope* functionScopeObject = JSNameScope::create(callFrame, function->name(), func, ReadOnly | DontDelete);
    4291             func->setScope(*globalData, functionScopeObject);
    4292         }
    4293 
    42944282        callFrame->uncheckedR(dst) = JSValue(func);
    42954283
  • trunk/Source/JavaScriptCore/jit/JITStubs.cpp

    r127394 r127698  
    21422142   
    21432143    ASSERT(stackFrame.callFrame->codeBlock()->codeType() != FunctionCode || !stackFrame.callFrame->codeBlock()->needsFullScopeChain() || stackFrame.callFrame->uncheckedR(stackFrame.callFrame->codeBlock()->activationRegister()).jsValue());
    2144     return stackFrame.args[0].function()->make(stackFrame.callFrame, stackFrame.callFrame->scope());
     2144    return JSFunction::create(stackFrame.callFrame, stackFrame.args[0].function(), stackFrame.callFrame->scope());
    21452145}
    21462146
     
    29832983
    29842984    FunctionExecutable* function = stackFrame.args[0].function();
    2985     JSFunction* func = function->make(callFrame, callFrame->scope());
     2985    JSFunction* func = JSFunction::create(callFrame, function, callFrame->scope());
    29862986    ASSERT(callFrame->codeBlock()->codeType() != FunctionCode || !callFrame->codeBlock()->needsFullScopeChain() || callFrame->uncheckedR(callFrame->codeBlock()->activationRegister()).jsValue());
    2987 
    2988     /*
    2989         The Identifier in a FunctionExpression can be referenced from inside
    2990         the FunctionExpression's FunctionBody to allow the function to call
    2991         itself recursively. However, unlike in a FunctionDeclaration, the
    2992         Identifier in a FunctionExpression cannot be referenced from and
    2993         does not affect the scope enclosing the FunctionExpression.
    2994      */
    2995     if (!function->name().isNull()) {
    2996         JSNameScope* functionScopeObject = JSNameScope::create(callFrame, function->name(), func, ReadOnly | DontDelete);
    2997         func->setScope(callFrame->globalData(), functionScopeObject);
    2998     }
    29992987
    30002988    return func;
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

    r127393 r127698  
    12611261    dataLog("Creating function!\n");
    12621262#endif
    1263     LLINT_RETURN(codeBlock->functionDecl(pc[2].u.operand)->make(exec, exec->scope()));
     1263    LLINT_RETURN(JSFunction::create(exec, codeBlock->functionDecl(pc[2].u.operand), exec->scope()));
    12641264}
    12651265
     
    12691269    CodeBlock* codeBlock = exec->codeBlock();
    12701270    FunctionExecutable* function = codeBlock->functionExpr(pc[2].u.operand);
    1271     JSFunction* func = function->make(exec, exec->scope());
    1272    
    1273     if (!function->name().isNull()) {
    1274         JSNameScope* functionScopeObject = JSNameScope::create(exec, function->name(), func, ReadOnly | DontDelete);
    1275         func->setScope(globalData, functionScopeObject);
    1276     }
     1271    JSFunction* func = JSFunction::create(exec, function, exec->scope());
    12771272   
    12781273    LLINT_RETURN(func);
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r127191 r127698  
    4141
    4242template <typename LexerType>
    43 Parser<LexerType>::Parser(JSGlobalData* globalData, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode)
     43Parser<LexerType>::Parser(JSGlobalData* globalData, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode)
    4444    : m_globalData(globalData)
    4545    , m_source(&source)
     
    7272            scope->declareParameter(&parameters->at(i));
    7373    }
     74    if (!name.isNull())
     75        scope->declareCallee(&name);
    7476    next();
    7577    m_lexer->setLastLineNumber(tokenLine());
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r127574 r127698  
    209209    bool isFunctionBoundary() { return m_isFunctionBoundary; }
    210210
     211    void declareCallee(const Identifier* ident)
     212    {
     213        m_declaredVariables.add(ident->ustring().impl());
     214    }
     215
    211216    bool declareVariable(const Identifier* ident)
    212217    {
     
    383388
    384389public:
    385     Parser(JSGlobalData*, const SourceCode&, FunctionParameters*, JSParserStrictness, JSParserMode);
     390    Parser(JSGlobalData*, const SourceCode&, FunctionParameters*, const Identifier&, JSParserStrictness, JSParserMode);
    386391    ~Parser();
    387392
     
    10211026
    10221027template <class ParsedNode>
    1023 PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, Debugger* debugger, ExecState* execState, JSObject** exception)
     1028PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode, Debugger* debugger, ExecState* execState, JSObject** exception)
    10241029{
    10251030    SamplingRegion samplingRegion("Parsing");
     
    10281033
    10291034    if (source.provider()->data()->is8Bit()) {
    1030         Parser< Lexer<LChar> > parser(globalData, source, parameters, strictness, parserMode);
     1035        Parser< Lexer<LChar> > parser(globalData, source, parameters, name, strictness, parserMode);
    10311036        return parser.parse<ParsedNode>(lexicalGlobalObject, debugger, execState, exception);
    10321037    }
    1033     Parser< Lexer<UChar> > parser(globalData, source, parameters, strictness, parserMode);
     1038    Parser< Lexer<UChar> > parser(globalData, source, parameters, name, strictness, parserMode);
    10341039    return parser.parse<ParsedNode>(lexicalGlobalObject, debugger, execState, exception);
    10351040}
  • trunk/Source/JavaScriptCore/runtime/Executable.cpp

    r127505 r127698  
    134134const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) };
    135135
    136 FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext)
    137     : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, source, inStrictContext)
     136FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, FunctionBodyNode* node)
     137    : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, node->source(), node->isStrictMode())
    138138    , m_numCapturedVariables(0)
    139     , m_forceUsesArguments(forceUsesArguments)
    140     , m_parameters(parameters)
    141     , m_name(name)
    142     , m_inferredName(inferredName.isNull() ? globalData.propertyNames->emptyIdentifier : inferredName)
    143 {
    144 }
    145 
    146 FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext)
    147     : ScriptExecutable(exec->globalData().functionExecutableStructure.get(), exec, source, inStrictContext)
    148     , m_numCapturedVariables(0)
    149     , m_forceUsesArguments(forceUsesArguments)
    150     , m_parameters(parameters)
    151     , m_name(name)
    152     , m_inferredName(inferredName.isNull() ? exec->globalData().propertyNames->emptyIdentifier : inferredName)
    153 {
     139    , m_forceUsesArguments(node->usesArguments())
     140    , m_parameters(node->parameters())
     141    , m_name(node->ident())
     142    , m_inferredName(node->inferredName().isNull() ? globalData.propertyNames->emptyIdentifier : node->inferredName())
     143{
     144    m_firstLine = node->lineNo();
     145    m_lastLine = node->lastLine();
    154146}
    155147
     
    211203        if (!lexicalGlobalObject->evalEnabled())
    212204            return throwError(exec, createEvalError(exec, ASCIILiteral("Eval is disabled")));
    213         RefPtr<EvalNode> evalNode = parse<EvalNode>(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, EvalNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
     205        RefPtr<EvalNode> evalNode = parse<EvalNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), isStrictMode() ? JSParseStrict : JSParseNormal, EvalNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
    214206        if (!evalNode) {
    215207            ASSERT(exception);
     
    294286    JSGlobalData* globalData = &exec->globalData();
    295287    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    296     RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
     288    RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
    297289    if (programNode)
    298290        return 0;
     
    336328        m_programCodeBlock = newCodeBlock.release();
    337329    } else {
    338         RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
     330        RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), isStrictMode() ? JSParseStrict : JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
    339331        if (!programNode) {
    340332            ASSERT(exception);
     
    479471    JSGlobalData* globalData = scope->globalData();
    480472    JSGlobalObject* globalObject = scope->globalObject();
    481     RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(globalData, globalObject, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, FunctionBodyNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, 0, 0, &exception);
     473    RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(
     474        globalData,
     475        globalObject,
     476        m_source,
     477        m_parameters.get(),
     478        name(),
     479        isStrictMode() ? JSParseStrict : JSParseNormal,
     480        FunctionBodyNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode,
     481        0,
     482        0,
     483        &exception
     484    );
    482485
    483486    if (!body) {
     
    648651}
    649652
    650 FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
     653FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
    651654{
    652655    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    653     RefPtr<ProgramNode> program = parse<ProgramNode>(&exec->globalData(), lexicalGlobalObject, source, 0, JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, debugger, exec, exception);
     656    RefPtr<ProgramNode> program = parse<ProgramNode>(&exec->globalData(), lexicalGlobalObject, source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, debugger, exec, exception);
    654657    if (!program) {
    655658        ASSERT(*exception);
     
    657660    }
    658661
    659     // Uses of this function that would not result in a single function expression are invalid.
     662    // This function assumes an input string that would result in a single anonymous function expression.
    660663    StatementNode* exprStatement = program->singleStatement();
    661664    ASSERT(exprStatement);
     
    666669    FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body();
    667670    ASSERT(body);
    668 
    669     return FunctionExecutable::create(exec->globalData(), functionName, functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
     671    ASSERT(body->ident().isNull());
     672
     673    FunctionExecutable* functionExecutable = FunctionExecutable::create(exec->globalData(), body);
     674    functionExecutable->m_nameValue.set(exec->globalData(), functionExecutable, jsString(&exec->globalData(), name.ustring()));
     675    return functionExecutable;
    670676}
    671677
  • trunk/Source/JavaScriptCore/runtime/Executable.h

    r127374 r127698  
    540540        typedef ScriptExecutable Base;
    541541
    542         static FunctionExecutable* create(ExecState* exec, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
    543         {
    544             FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
    545             executable->finishCreation(exec->globalData(), name, firstLine, lastLine);
     542        static FunctionExecutable* create(JSGlobalData& globalData, FunctionBodyNode* node)
     543        {
     544            FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, node);
     545            executable->finishCreation(globalData);
    546546            return executable;
    547547        }
    548 
    549         static FunctionExecutable* create(JSGlobalData& globalData, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
    550         {
    551             FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
    552             executable->finishCreation(globalData, name, firstLine, lastLine);
    553             return executable;
    554         }
     548        static FunctionExecutable* fromGlobalCode(const Identifier& name, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
    555549
    556550        static void destroy(JSCell*);
    557551
    558         JSFunction* make(ExecState* exec, JSScope* scope)
    559         {
    560             return JSFunction::create(exec, this, scope);
    561         }
    562        
    563552        // Returns either call or construct bytecode. This can be appropriate
    564553        // for answering questions that that don't vary between call and construct --
     
    709698        void clearCodeIfNotCompiling();
    710699        static void visitChildren(JSCell*, SlotVisitor&);
    711         static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
    712700        static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
    713701        {
     
    722710
    723711    protected:
    724         void finishCreation(JSGlobalData& globalData, const Identifier& name, int firstLine, int lastLine)
     712        void finishCreation(JSGlobalData& globalData)
    725713        {
    726714            Base::finishCreation(globalData);
    727             m_firstLine = firstLine;
    728             m_lastLine = lastLine;
    729             m_nameValue.set(globalData, this, jsString(&globalData, name.ustring()));
     715            m_nameValue.set(globalData, this, jsString(&globalData, name().ustring()));
    730716        }
    731717
    732718    private:
    733         FunctionExecutable(JSGlobalData&, const Identifier& name, const Identifier& inferredName, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool);
    734         FunctionExecutable(ExecState*, const Identifier& name, const Identifier& inferredName, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool);
     719        FunctionExecutable(JSGlobalData&, FunctionBodyNode*);
    735720
    736721        JSObject* compileForCallInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX);
  • trunk/Source/JavaScriptCore/runtime/JSNameScope.h

    r127363 r127698  
    3939    static JSNameScope* create(ExecState* exec, const Identifier& identifier, JSValue value, unsigned attributes)
    4040    {
    41         JSNameScope* scopeObject = new (NotNull, allocateCell<JSNameScope>(*exec->heap())) JSNameScope(exec);
     41        JSNameScope* scopeObject = new (NotNull, allocateCell<JSNameScope>(*exec->heap())) JSNameScope(exec, exec->scope());
     42        scopeObject->finishCreation(exec, identifier, value, attributes);
     43        return scopeObject;
     44    }
     45
     46    static JSNameScope* create(ExecState* exec, const Identifier& identifier, JSValue value, unsigned attributes, JSScope* next)
     47    {
     48        JSNameScope* scopeObject = new (NotNull, allocateCell<JSNameScope>(*exec->heap())) JSNameScope(exec, next);
    4249        scopeObject->finishCreation(exec, identifier, value, attributes);
    4350        return scopeObject;
     
    6572
    6673private:
    67     JSNameScope(ExecState* exec)
     74    JSNameScope(ExecState* exec, JSScope* next)
    6875        : Base(
    6976            exec->globalData(),
    7077            exec->lexicalGlobalObject()->nameScopeStructure(),
    7178            reinterpret_cast<Register*>(&m_registerStore + 1),
    72             exec->scope()
     79            next
    7380        )
    7481    {
Note: See TracChangeset for help on using the changeset viewer.