Ignore:
Timestamp:
Nov 6, 2012, 4:13:54 PM (13 years ago)
Author:
[email protected]
Message:

Reduce parser overhead in JSC
https://bugs.webkit.org/show_bug.cgi?id=101127

Reviewed by Filip Pizlo.

An exciting journey into the world of architecture in which our hero
adds yet another layer to JSC codegeneration.

This patch adds a marginally more compact form of bytecode that is
free from any data specific to a given execution context, and that
does store any data structures necessary for execution. To actually
execute this UnlinkedBytecode we still need to instantiate a real
CodeBlock, but this is a much faster linear time operation than any
of the earlier parsing or code generation passes.

As the unlinked code is context free we can then simply use a cache
from source to unlinked code mapping to completely avoid all of the
old parser overhead. The cache is currently very simple and memory
heavy, using the complete source text as a key (rather than SourceCode
or equivalent), and a random eviction policy.

This seems to produce a substantial win when loading identical content
in different contexts.

  • API/tests/testapi.c:

(main):

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/CodeBlock.cpp:
  • bytecode/CodeBlock.h:

Moved a number of fields, and a bunch of logic to UnlinkedCodeBlock.h/cpp

  • bytecode/Opcode.h:

Added a global const init no op instruction needed to get correct
behaviour without any associated semantics.

  • bytecode/UnlinkedCodeBlock.cpp: Added.
  • bytecode/UnlinkedCodeBlock.h: Added.

A fairly shallow, GC allocated version of the old CodeBlock
classes with a 32bit instruction size, and just metadata
size tracking.

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

Replace direct access to m_symbolTable with access through
symbolTable(). ProgramCode no longer has a symbol table at
all so some previously unconditional (and pointless) uses
of symbolTable get null checks.
A few other changes to deal with type changes due to us generating
unlinked code (eg. pointer free, so profile indices rather than
pointers).

  • dfg/DFGByteCodeParser.cpp:
  • dfg/DFGCapabilities.h:

Support global_init_nop

  • interpreter/Interpreter.cpp:

Now get the ProgramExecutable to initialise new global properties
before starting execution.

  • jit/JIT.cpp:
  • jit/JITDriver.h:
  • jit/JITStubs.cpp:
  • llint/LLIntData.cpp:
  • llint/LLIntSlowPaths.cpp:
  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:

Adding init_global_const_nop everywhere else

  • parser/Parser.h:
  • parser/ParserModes.h: Added.
  • parser/ParserTokens.h:

Parser no longer needs a global object or callframe to function

  • runtime/CodeCache.cpp: Added.
  • runtime/CodeCache.h: Added.

A simple, random eviction, Source->UnlinkedCode cache

  • runtime/Executable.cpp:
  • runtime/Executable.h:

Executables now reference their unlinked counterparts, and
request code specifically for the target global object.

  • runtime/JSGlobalData.cpp:
  • runtime/JSGlobalData.h:

GlobalData now owns a CodeCache and a set of new structures
for the unlinked code types.

  • runtime/JSGlobalObject.cpp:
  • runtime/JSGlobalObject.h:

Utility functions used by executables to perform compilation

  • runtime/JSType.h: Add new JSTypes for unlinked code
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/Executable.cpp

    r129453 r133688  
    2727#include "Executable.h"
    2828
     29#include "BatchedTransitionOptimizer.h"
    2930#include "BytecodeGenerator.h"
    3031#include "CodeBlock.h"
     
    134135const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) };
    135136
    136 FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, FunctionBodyNode* node)
    137     : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, node->source(), node->isStrictMode())
    138     , m_forceUsesArguments(node->usesArguments())
    139     , m_parameters(node->parameters())
    140     , m_name(node->ident())
    141     , m_inferredName(node->inferredName().isNull() ? globalData.propertyNames->emptyIdentifier : node->inferredName())
    142     , m_functionNameIsInScopeToggle(node->functionNameIsInScopeToggle())
    143 {
    144     m_firstLine = node->lineNo();
    145     m_lastLine = node->lastLine();
     137FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine)
     138    : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, source, unlinkedExecutable->isInStrictContext())
     139    , m_unlinkedExecutable(globalData, this, unlinkedExecutable)
     140{
     141    ASSERT(!source.isNull());
     142    ASSERT(source.length());
     143    m_firstLine = firstLine;
     144    m_lastLine = lastLine;
    146145}
    147146
     
    192191    UNUSED_PARAM(bytecodeIndex);
    193192#endif
    194     JSObject* exception = 0;
    195193    JSGlobalData* globalData = &exec->globalData();
    196194    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
     
    201199        m_evalCodeBlock = newCodeBlock.release();
    202200    } else {
     201        UNUSED_PARAM(scope);
     202        UNUSED_PARAM(globalData);
     203        UNUSED_PARAM(lexicalGlobalObject);
    203204        if (!lexicalGlobalObject->evalEnabled())
    204205            return throwError(exec, createEvalError(exec, lexicalGlobalObject->evalDisabledErrorMessage()));
    205         RefPtr<EvalNode> evalNode = parse<EvalNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), isStrictMode() ? JSParseStrict : JSParseNormal, EvalNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
    206         if (!evalNode) {
    207             ASSERT(exception);
     206
     207        JSObject* exception = 0;
     208        UnlinkedEvalCodeBlock* unlinkedEvalCode = lexicalGlobalObject->createEvalCodeBlock(exec, this, &exception);
     209        if (!unlinkedEvalCode)
    208210            return exception;
    209         }
    210         recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine());
    211        
    212         JSGlobalObject* globalObject = scope->globalObject();
    213        
     211
    214212        OwnPtr<CodeBlock> previousCodeBlock = m_evalCodeBlock.release();
    215213        ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock);
    216         m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scope->localDepth(), previousCodeBlock.release()));
    217         OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scope, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get(), !!m_evalCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation)));
    218         if ((exception = generator->generate())) {
    219             m_evalCodeBlock = static_pointer_cast<EvalCodeBlock>(m_evalCodeBlock->releaseAlternative());
    220             evalNode->destroyData();
    221             return exception;
    222         }
    223        
    224         evalNode->destroyData();
     214        m_unlinkedEvalCodeBlock.set(*globalData, this, unlinkedEvalCode);
     215        m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, unlinkedEvalCode, lexicalGlobalObject, source().provider(), scope->localDepth(), previousCodeBlock.release()));
    225216        m_evalCodeBlock->copyPostParseDataFromAlternative();
    226217    }
     
    258249    if (thisObject->m_evalCodeBlock)
    259250        thisObject->m_evalCodeBlock->visitAggregate(visitor);
     251    visitor.append(&thisObject->m_unlinkedEvalCodeBlock);
    260252}
    261253
     
    273265{
    274266    m_evalCodeBlock.clear();
     267    m_unlinkedEvalCodeBlock.clear();
    275268    Base::clearCode();
    276269}
     
    278271JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
    279272{
    280     JSObject* exception = 0;
     273    ParserError error;
    281274    JSGlobalData* globalData = &exec->globalData();
    282275    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    283     RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
     276    RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error);
    284277    if (programNode)
    285278        return 0;
    286     ASSERT(exception);
    287     return exception;
     279    ASSERT(error.m_type != ParserError::ErrorNone);
     280    return error.toErrorObject(lexicalGlobalObject, m_source);
    288281}
    289282
     
    311304   
    312305#if !ENABLE(JIT)
     306    UNUSED_PARAM(exec);
    313307    UNUSED_PARAM(jitType);
    314308    UNUSED_PARAM(bytecodeIndex);
    315309#endif
    316     JSObject* exception = 0;
    317     JSGlobalData* globalData = &exec->globalData();
    318     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    319    
    320310    if (!!m_programCodeBlock) {
    321311        OwnPtr<ProgramCodeBlock> newCodeBlock = adoptPtr(new ProgramCodeBlock(CodeBlock::CopyParsedBlock, *m_programCodeBlock));
     
    323313        m_programCodeBlock = newCodeBlock.release();
    324314    } else {
    325         RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), isStrictMode() ? JSParseStrict : JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
    326         if (!programNode) {
    327             ASSERT(exception);
    328             return exception;
    329         }
    330         recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine());
    331 
    332315        JSGlobalObject* globalObject = scope->globalObject();
    333    
    334         OwnPtr<CodeBlock> previousCodeBlock = m_programCodeBlock.release();
    335         ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock);
    336         m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider(), previousCodeBlock.release()));
    337         OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), scope, globalObject->symbolTable(), m_programCodeBlock.get(), !!m_programCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation)));
    338         if ((exception = generator->generate())) {
    339             m_programCodeBlock = static_pointer_cast<ProgramCodeBlock>(m_programCodeBlock->releaseAlternative());
    340             programNode->destroyData();
    341             return exception;
    342         }
    343 
    344         programNode->destroyData();
     316        m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, m_unlinkedProgramCodeBlock.get(), globalObject, source().provider(), m_programCodeBlock.release()));
    345317        m_programCodeBlock->copyPostParseDataFromAlternative();
    346318    }
     
    377349    m_programCodeBlock->unlinkCalls();
    378350#endif
     351}
     352
     353int ProgramExecutable::addGlobalVar(JSGlobalObject* globalObject, const Identifier& ident, ConstantMode constantMode, FunctionMode functionMode)
     354{
     355    // Try to share the symbolTable if possible
     356    SharedSymbolTable* symbolTable = globalObject->symbolTable();
     357    UNUSED_PARAM(functionMode);
     358    int index = symbolTable->size();
     359    SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0);
     360    if (functionMode == IsFunctionToSpecialize)
     361        newEntry.attemptToWatch();
     362    SymbolTable::AddResult result = symbolTable->add(ident.impl(), newEntry);
     363    if (!result.isNewEntry) {
     364        result.iterator->value.notifyWrite();
     365        index = result.iterator->value.getIndex();
     366    }
     367    return index;
     368}
     369
     370JSObject* ProgramExecutable::initalizeGlobalProperties(JSGlobalData& globalData, CallFrame* callFrame, JSScope* scope)
     371{
     372    ASSERT(scope);
     373    JSGlobalObject* globalObject = scope->globalObject();
     374    ASSERT(globalObject);
     375    ASSERT(&globalObject->globalData() == &globalData);
     376
     377    JSObject* exception = 0;
     378    UnlinkedProgramCodeBlock* unlinkedCode = globalObject->createProgramCodeBlock(callFrame, this, &exception);
     379    if (exception)
     380        return exception;
     381
     382    m_unlinkedProgramCodeBlock.set(globalData, this, unlinkedCode);
     383
     384    BatchedTransitionOptimizer optimizer(globalData, globalObject);
     385
     386    const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCode->variableDeclarations();
     387    const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCode->functionDeclarations();
     388
     389    size_t newGlobals = variableDeclarations.size() + functionDeclarations.size();
     390    if (!newGlobals)
     391        return 0;
     392    globalObject->addRegisters(newGlobals);
     393    CallFrame* globalExec = globalObject->globalExec();
     394
     395    for (size_t i = 0; i < functionDeclarations.size(); ++i) {
     396        bool propertyDidExist = globalObject->removeDirect(globalData, functionDeclarations[i].first); // Newly declared functions overwrite existing properties.
     397        UnlinkedFunctionExecutable* unlinkedFunctionExecutable = functionDeclarations[i].second.get();
     398        JSValue value = JSFunction::create(globalExec, unlinkedFunctionExecutable->link(globalData, m_source, lineNo(), 0), scope);
     399        int index = addGlobalVar(globalObject, functionDeclarations[i].first, IsVariable,
     400            !propertyDidExist ? IsFunctionToSpecialize : NotFunctionOrNotSpecializable);
     401        globalObject->registerAt(index).set(globalData, globalObject, value);
     402    }
     403
     404    for (size_t i = 0; i < variableDeclarations.size(); ++i) {
     405        if (globalObject->hasProperty(globalExec, variableDeclarations[i].first))
     406            continue;
     407        addGlobalVar(globalObject, variableDeclarations[i].first,
     408            (variableDeclarations[i].second & DeclarationStacks::IsConstant) ? IsConstant : IsVariable,
     409            NotFunctionOrNotSpecializable);
     410    }
     411    return 0;
    379412}
    380413
     
    386419    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
    387420    ScriptExecutable::visitChildren(thisObject, visitor);
     421    visitor.append(&thisObject->m_unlinkedProgramCodeBlock);
    388422    if (thisObject->m_programCodeBlock)
    389423        thisObject->m_programCodeBlock->visitAggregate(visitor);
     
    393427{
    394428    m_programCodeBlock.clear();
     429    m_unlinkedProgramCodeBlock.clear();
    395430    Base::clearCode();
    396431}
     
    439474bool FunctionExecutable::jitCompileForCall(ExecState* exec)
    440475{
    441     return jitCompileFunctionIfAppropriate(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail);
     476    return jitCompileFunctionIfAppropriate(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail);
    442477}
    443478
    444479bool FunctionExecutable::jitCompileForConstruct(ExecState* exec)
    445480{
    446     return jitCompileFunctionIfAppropriate(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail);
     481    return jitCompileFunctionIfAppropriate(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail);
    447482}
    448483#endif
     
    453488}
    454489
    455 PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(JSScope* scope, CompilationKind compilationKind, CodeSpecializationKind specializationKind, JSObject*& exception)
     490PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(JSScope* scope, CodeSpecializationKind specializationKind, JSObject*& exception)
    456491{
    457492    if (!!codeBlockFor(specializationKind))
    458493        return adoptPtr(new FunctionCodeBlock(CodeBlock::CopyParsedBlock, *codeBlockFor(specializationKind)));
    459    
    460     exception = 0;
     494
    461495    JSGlobalData* globalData = scope->globalData();
    462496    JSGlobalObject* globalObject = scope->globalObject();
    463     RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(
    464         globalData,
    465         globalObject,
    466         m_source,
    467         m_parameters.get(),
    468         name(),
    469         isStrictMode() ? JSParseStrict : JSParseNormal,
    470         FunctionBodyNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode,
    471         0,
    472         0,
    473         &exception
    474     );
    475 
    476     if (!body) {
    477         ASSERT(exception);
     497    ParserError error;
     498    DebuggerMode debuggerMode = globalObject->hasDebugger() ? DebuggerOn : DebuggerOff;
     499    ProfilerMode profilerMode = globalObject->hasProfiler() ? ProfilerOn : ProfilerOff;
     500    UnlinkedFunctionCodeBlock* unlinkedCodeBlock = m_unlinkedExecutable->codeBlockFor(*globalData, m_source, specializationKind, debuggerMode, profilerMode, error);
     501    recordParse(m_unlinkedExecutable->features(), m_unlinkedExecutable->hasCapturedVariables(), lineNo(), lastLine());
     502
     503    if (!unlinkedCodeBlock) {
     504        exception = error.toErrorObject(globalObject, m_source);
    478505        return nullptr;
    479506    }
    480     if (m_forceUsesArguments)
    481         body->setUsesArguments();
    482     body->finishParsing(m_parameters, m_name, m_functionNameIsInScopeToggle);
    483     recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
    484 
    485     OwnPtr<FunctionCodeBlock> result;
    486     ASSERT((compilationKind == FirstCompilation) == !codeBlockFor(specializationKind));
    487     result = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), specializationKind == CodeForConstruct));
    488     OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scope, result->symbolTable(), result.get(), compilationKind)));
    489     exception = generator->generate();
    490     body->destroyData();
    491     if (exception)
    492         return nullptr;
    493 
     507
     508    OwnPtr<FunctionCodeBlock> result = adoptPtr(new FunctionCodeBlock(this, unlinkedCodeBlock, globalObject, source().provider(), source().startOffset()));
    494509    result->copyPostParseDataFrom(codeBlockFor(specializationKind).get());
    495510    return result.release();
    496511}
     512
    497513
    498514JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, JSScope* scope, JITCode::JITType jitType, unsigned bytecodeIndex)
     
    508524    ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForCall);
    509525    JSObject* exception;
    510     OwnPtr<FunctionCodeBlock> newCodeBlock = produceCodeBlockFor(scope, !!m_codeBlockForCall ? OptimizingCompilation : FirstCompilation, CodeForCall, exception);
     526    OwnPtr<FunctionCodeBlock> newCodeBlock = produceCodeBlockFor(scope, CodeForCall, exception);
    511527    if (!newCodeBlock)
    512528        return exception;
     
    517533    m_numParametersForCall = m_codeBlockForCall->numParameters();
    518534    ASSERT(m_numParametersForCall);
    519     m_symbolTable.set(exec->globalData(), this, m_codeBlockForCall->symbolTable());
    520 
    521 #if ENABLE(JIT)
    522     if (!prepareFunctionForExecution(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, jitType, bytecodeIndex, CodeForCall))
     535
     536#if ENABLE(JIT)
     537    if (!prepareFunctionForExecution(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, jitType, bytecodeIndex, CodeForCall))
    523538        return 0;
    524539#endif
     
    545560    ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForConstruct);
    546561    JSObject* exception;
    547     OwnPtr<FunctionCodeBlock> newCodeBlock = produceCodeBlockFor(scope, !!m_codeBlockForConstruct ? OptimizingCompilation : FirstCompilation, CodeForConstruct, exception);
     562    OwnPtr<FunctionCodeBlock> newCodeBlock = produceCodeBlockFor(scope, CodeForConstruct, exception);
    548563    if (!newCodeBlock)
    549564        return exception;
     
    554569    m_numParametersForConstruct = m_codeBlockForConstruct->numParameters();
    555570    ASSERT(m_numParametersForConstruct);
    556     m_symbolTable.set(exec->globalData(), this, m_codeBlockForConstruct->symbolTable());
    557 
    558 #if ENABLE(JIT)
    559     if (!prepareFunctionForExecution(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, jitType, bytecodeIndex, CodeForConstruct))
     571
     572#if ENABLE(JIT)
     573    if (!prepareFunctionForExecution(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, jitType, bytecodeIndex, CodeForConstruct))
    560574        return 0;
    561575#endif
     
    593607    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
    594608    ScriptExecutable::visitChildren(thisObject, visitor);
    595     visitor.append(&thisObject->m_nameValue);
    596     visitor.append(&thisObject->m_symbolTable);
    597609    if (thisObject->m_codeBlockForCall)
    598610        thisObject->m_codeBlockForCall->visitAggregate(visitor);
    599611    if (thisObject->m_codeBlockForConstruct)
    600612        thisObject->m_codeBlockForConstruct->visitAggregate(visitor);
     613    visitor.append(&thisObject->m_unlinkedExecutable);
    601614}
    602615
     
    608621}
    609622
     623void FunctionExecutable::clearUnlinkedCodeIfNotCompiling()
     624{
     625    if (isCompiling())
     626        return;
     627    m_unlinkedExecutable->clearCode();
     628}
     629
    610630void FunctionExecutable::clearCode()
    611631{
    612632    m_codeBlockForCall.clear();
    613633    m_codeBlockForConstruct.clear();
     634    m_unlinkedExecutable->clearCode();
    614635    Base::clearCode();
    615636}
     
    631652FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
    632653{
    633     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    634     RefPtr<ProgramNode> program = parse<ProgramNode>(&exec->globalData(), lexicalGlobalObject, source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, debugger, exec, exception);
    635     if (!program) {
    636         ASSERT(*exception);
    637         return 0;
    638     }
    639 
    640     // This function assumes an input string that would result in a single anonymous function expression.
    641     StatementNode* exprStatement = program->singleStatement();
    642     ASSERT(exprStatement);
    643     ASSERT(exprStatement->isExprStatement());
    644     ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr();
    645     ASSERT(funcExpr);
    646     ASSERT(funcExpr->isFuncExprNode());
    647     FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body();
    648     ASSERT(body);
    649     ASSERT(body->ident().isNull());
    650 
    651     FunctionExecutable* functionExecutable = FunctionExecutable::create(exec->globalData(), body);
    652     functionExecutable->m_nameValue.set(exec->globalData(), functionExecutable, jsString(&exec->globalData(), name.string()));
    653     return functionExecutable;
     654    UnlinkedFunctionExecutable* unlinkedFunction = UnlinkedFunctionExecutable::fromGlobalCode(name, exec, debugger, source, exception);
     655    if (!unlinkedFunction)
     656        return 0;
     657    unsigned firstLine = source.firstLine() + unlinkedFunction->firstLineOffset();
     658    unsigned startOffset = source.startOffset() + unlinkedFunction->startOffset();
     659    unsigned sourceLength = unlinkedFunction->sourceLength();
     660    SourceCode functionSource(source.provider(), startOffset, startOffset + sourceLength, firstLine);
     661    return FunctionExecutable::create(exec->globalData(), functionSource, unlinkedFunction, firstLine, unlinkedFunction->lineCount());
    654662}
    655663
    656664String FunctionExecutable::paramString() const
    657665{
    658     FunctionParameters& parameters = *m_parameters;
    659     StringBuilder builder;
    660     for (size_t pos = 0; pos < parameters.size(); ++pos) {
    661         if (!builder.isEmpty())
    662             builder.appendLiteral(", ");
    663         builder.append(parameters[pos].string());
    664     }
    665     return builder.toString();
    666 }
    667 
    668 }
     666    return m_unlinkedExecutable->paramString();
     667}
     668
     669}
Note: See TracChangeset for help on using the changeset viewer.