Ignore:
Timestamp:
Jan 7, 2009, 5:46:14 PM (16 years ago)
Author:
[email protected]
Message:

2009-01-07 Sam Weinig <[email protected]>

Reviewed by Geoffrey Garen.

<rdar://problem/6469060> Don't store exception information for a CodeBlock until first exception is thrown

Don't initially store exception information (lineNumber/expressionRange/getByIdExcecptionInfo)
in CodeBlocks blocks. Instead, re-parse for the data on demand and cache it then.

One important change that was needed to make this work was to pad op_get_global_var with nops to
be the same length as op_resolve_global, since one could be replaced for the other on re-parsing,
and we want to keep the offsets bytecode offsets the same.

1.3MB improvement on Membuster head.

  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump): Update op_get_global_var to account for the padding. (JSC::CodeBlock::dumpStatistics): Add more statistic dumping. (JSC::CodeBlock::CodeBlock): Initialize m_exceptionInfo. (JSC::CodeBlock::reparseForExceptionInfoIfNecessary): Re-parses the CodeBlocks associated SourceCode and steals the ExceptionInfo from it. (JSC::CodeBlock::lineNumberForBytecodeOffset): Creates the exception info on demand. (JSC::CodeBlock::expressionRangeForBytecodeOffset): Ditto. (JSC::CodeBlock::getByIdExceptionInfoForBytecodeOffset): Ditto.
  • bytecode/CodeBlock.h: (JSC::CodeBlock::numberOfExceptionHandlers): Updated to account for m_exceptionInfo indirection. (JSC::CodeBlock::addExceptionHandler): Ditto. (JSC::CodeBlock::exceptionHandler): Ditto. (JSC::CodeBlock::clearExceptionInfo): Ditto. (JSC::CodeBlock::addExpressionInfo): Ditto. (JSC::CodeBlock::addGetByIdExceptionInfo): Ditto. (JSC::CodeBlock::numberOfLineInfos): Ditto. (JSC::CodeBlock::addLineInfo): Ditto. (JSC::CodeBlock::lastLineInfo): Ditto.
  • bytecode/Opcode.h: Change length of op_get_global_var to match op_resolve_global.
  • bytecode/SamplingTool.cpp: (JSC::SamplingTool::dump): Add comment indicating why it is okay not to pass a CallFrame.
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): Clear the exception info after generation for Function and Eval Code when not in regenerate for exception info mode. (JSC::BytecodeGenerator::BytecodeGenerator): Initialize m_regeneratingForExceptionInfo to false. (JSC::BytecodeGenerator::emitGetScopedVar): Pad op_get_global_var with 2 nops.
  • bytecompiler/BytecodeGenerator.h: (JSC::BytecodeGenerator::setRegeneratingForExcpeptionInfo): Added.
  • interpreter/Interpreter.cpp: (JSC::Interpreter::throwException): Pass the CallFrame to exception info accessors. (JSC::Interpreter::privateExecute): Ditto. (JSC::Interpreter::retrieveLastCaller): Ditto. (JSC::Interpreter::cti_op_new_error): Ditto.
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): Pass the current bytecode offset instead of hard coding the line number, the stub will do the accessing if it gets called.
  • parser/Nodes.cpp: (JSC::ProgramNode::emitBytecode): Moved. (JSC::ProgramNode::generateBytecode): Moved. (JSC::EvalNode::create): Moved. (JSC::EvalNode::bytecodeForExceptionInfoReparse): Added. (JSC::FunctionBodyNode::generateBytecode): Rename reparse to reparseInPlace. (JSC::FunctionBodyNode::bytecodeForExceptionInfoReparse): Addded.
  • parser/Nodes.h: (JSC::ScopeNode::features): Added getter.
  • parser/Parser.cpp: (JSC::Parser::reparseInPlace): Renamed from reparse.
  • parser/Parser.h: (JSC::Parser::reparse): Added. Re-parses the passed in Node into a new Node.
  • runtime/ExceptionHelpers.cpp: (JSC::createUndefinedVariableError): Pass along CallFrame. (JSC::createInvalidParamError): Ditto. (JSC::createNotAConstructorError): Ditto. (JSC::createNotAFunctionError): Ditto. (JSC::createNotAnObjectError): Ditto.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/parser/Nodes.cpp

    r39534 r39697  
    22*  Copyright (C) 1999-2002 Harri Porten ([email protected])
    33*  Copyright (C) 2001 Peter Kelly ([email protected])
    4 *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
     4*  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
    55*  Copyright (C) 2007 Cameron Zwarich ([email protected])
    66*  Copyright (C) 2007 Maks Orlovich
     
    24502450}
    24512451
    2452 // ------------------------------ EvalNode -----------------------------
    2453 
    2454 EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
    2455     : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants)
    2456 {
    2457 }
    2458 
    2459 RegisterID* EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
    2460 {
    2461     generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine());
    2462 
    2463     RefPtr<RegisterID> dstRegister = generator.newTemporary();
    2464     generator.emitLoad(dstRegister.get(), jsUndefined());
    2465     statementListEmitCode(children(), generator, dstRegister.get());
    2466 
    2467     generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine());
    2468     generator.emitEnd(dstRegister.get());
    2469     return 0;
    2470 }
    2471 
    2472 void EvalNode::generateBytecode(ScopeChainNode* scopeChainNode)
    2473 {
    2474     ScopeChain scopeChain(scopeChainNode);
    2475     JSGlobalObject* globalObject = scopeChain.globalObject();
    2476 
    2477     m_code.set(new EvalCodeBlock(this, globalObject, source().provider()));
    2478 
    2479     BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get());
    2480     generator.generate();
    2481 
    2482     // Eval code needs to hang on to its declaration stacks to keep declaration info alive until Interpreter::execute time,
    2483     // so the entire ScopeNodeData cannot be destoyed.
    2484     children().clear();
    2485 }
    2486 
    2487 EvalNode* EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
    2488 {
    2489     return new EvalNode(globalData, children, varStack, funcStack, source, features, numConstants);
    2490 }
    2491 
    2492 // ------------------------------ FunctionBodyNode -----------------------------
    2493 
    2494 FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData)
    2495     : ScopeNode(globalData)
    2496     , m_parameters(0)
    2497     , m_parameterCount(0)
    2498     , m_refCount(0)
    2499 {
    2500 }
    2501 
    2502 FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
    2503     : ScopeNode(globalData, sourceCode, children, varStack, funcStack, features, numConstants)
    2504     , m_parameters(0)
    2505     , m_parameterCount(0)
    2506     , m_refCount(0)
    2507 {
    2508 }
    2509 
    2510 FunctionBodyNode::~FunctionBodyNode()
    2511 {
    2512     ASSERT(!m_refCount);
    2513     fastFree(m_parameters);
    2514 }
    2515 
    2516 void FunctionBodyNode::finishParsing(const SourceCode& source, ParameterNode* firstParameter)
    2517 {
    2518     Vector<Identifier> parameters;
    2519     for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam())
    2520         parameters.append(parameter->ident());
    2521     size_t count = parameters.size();
    2522 
    2523     setSource(source);
    2524     finishParsing(parameters.releaseBuffer(), count);
    2525 }
    2526 
    2527 void FunctionBodyNode::finishParsing(Identifier* parameters, size_t parameterCount)
    2528 {
    2529     ASSERT(!source().isNull());
    2530     m_parameters = parameters;
    2531     m_parameterCount = parameterCount;
    2532 }
    2533 
    2534 void FunctionBodyNode::mark()
    2535 {
    2536     if (m_code)
    2537         m_code->mark();
    2538 }
    2539 
    2540 FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData)
    2541 {
    2542     return new FunctionBodyNode(globalData);
    2543 }
    2544 
    2545 FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
    2546 {
    2547     return new FunctionBodyNode(globalData, children, varStack, funcStack, sourceCode, features, numConstants);
    2548 }
    2549 
    2550 void FunctionBodyNode::generateBytecode(ScopeChainNode* scopeChainNode)
    2551 {
    2552     // This branch is only necessary since you can still create a non-stub FunctionBodyNode by
    2553     // calling Parser::parse<FunctionBodyNode>().   
    2554     if (!data())
    2555         scopeChainNode->globalData->parser->reparse(scopeChainNode->globalData, this);
    2556     ASSERT(data());
    2557 
    2558     ScopeChain scopeChain(scopeChainNode);
    2559     JSGlobalObject* globalObject = scopeChain.globalObject();
    2560 
    2561     m_code.set(new CodeBlock(this, FunctionCode, source().provider(), source().startOffset()));
    2562 
    2563     BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get());
    2564     generator.generate();
    2565 
    2566     destroyData();
    2567 }
    2568 
    2569 RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
    2570 {
    2571     generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine());
    2572     statementListEmitCode(children(), generator, generator.ignoredResult());
    2573     if (!children().size() || !children().last()->isReturnNode()) {
    2574         RegisterID* r0 = generator.emitLoad(0, jsUndefined());
    2575         generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine());
    2576         generator.emitReturn(r0);
    2577     }
    2578     return 0;
    2579 }
    2580 
    25812452RegisterID* ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
    25822453{
     
    26052476}
    26062477
     2478// ------------------------------ EvalNode -----------------------------
     2479
     2480EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
     2481    : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants)
     2482{
     2483}
     2484
     2485EvalNode* EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
     2486{
     2487    return new EvalNode(globalData, children, varStack, funcStack, source, features, numConstants);
     2488}
     2489
     2490RegisterID* EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
     2491{
     2492    generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine());
     2493
     2494    RefPtr<RegisterID> dstRegister = generator.newTemporary();
     2495    generator.emitLoad(dstRegister.get(), jsUndefined());
     2496    statementListEmitCode(children(), generator, dstRegister.get());
     2497
     2498    generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine());
     2499    generator.emitEnd(dstRegister.get());
     2500    return 0;
     2501}
     2502
     2503void EvalNode::generateBytecode(ScopeChainNode* scopeChainNode)
     2504{
     2505    ScopeChain scopeChain(scopeChainNode);
     2506    JSGlobalObject* globalObject = scopeChain.globalObject();
     2507
     2508    m_code.set(new EvalCodeBlock(this, globalObject, source().provider()));
     2509
     2510    BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get());
     2511    generator.generate();
     2512
     2513    // Eval code needs to hang on to its declaration stacks to keep declaration info alive until Interpreter::execute time,
     2514    // so the entire ScopeNodeData cannot be destoyed.
     2515    children().clear();
     2516}
     2517
     2518EvalCodeBlock& EvalNode::bytecodeForExceptionInfoReparse(ScopeChainNode* scopeChainNode)
     2519{
     2520    ASSERT(!m_code);
     2521
     2522    ScopeChain scopeChain(scopeChainNode);
     2523    JSGlobalObject* globalObject = scopeChain.globalObject();
     2524
     2525    m_code.set(new EvalCodeBlock(this, globalObject, source().provider()));
     2526
     2527    BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get());
     2528    generator.setRegeneratingForExceptionInfo();
     2529    generator.generate();
     2530
     2531    return *m_code;
     2532}
     2533
     2534// ------------------------------ FunctionBodyNode -----------------------------
     2535
     2536FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData)
     2537    : ScopeNode(globalData)
     2538    , m_parameters(0)
     2539    , m_parameterCount(0)
     2540    , m_refCount(0)
     2541{
     2542}
     2543
     2544FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
     2545    : ScopeNode(globalData, sourceCode, children, varStack, funcStack, features, numConstants)
     2546    , m_parameters(0)
     2547    , m_parameterCount(0)
     2548    , m_refCount(0)
     2549{
     2550}
     2551
     2552FunctionBodyNode::~FunctionBodyNode()
     2553{
     2554    ASSERT(!m_refCount);
     2555    fastFree(m_parameters);
     2556}
     2557
     2558void FunctionBodyNode::finishParsing(const SourceCode& source, ParameterNode* firstParameter)
     2559{
     2560    Vector<Identifier> parameters;
     2561    for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam())
     2562        parameters.append(parameter->ident());
     2563    size_t count = parameters.size();
     2564
     2565    setSource(source);
     2566    finishParsing(parameters.releaseBuffer(), count);
     2567}
     2568
     2569void FunctionBodyNode::finishParsing(Identifier* parameters, size_t parameterCount)
     2570{
     2571    ASSERT(!source().isNull());
     2572    m_parameters = parameters;
     2573    m_parameterCount = parameterCount;
     2574}
     2575
     2576void FunctionBodyNode::mark()
     2577{
     2578    if (m_code)
     2579        m_code->mark();
     2580}
     2581
     2582FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData)
     2583{
     2584    return new FunctionBodyNode(globalData);
     2585}
     2586
     2587FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
     2588{
     2589    return new FunctionBodyNode(globalData, children, varStack, funcStack, sourceCode, features, numConstants);
     2590}
     2591
     2592void FunctionBodyNode::generateBytecode(ScopeChainNode* scopeChainNode)
     2593{
     2594    // This branch is only necessary since you can still create a non-stub FunctionBodyNode by
     2595    // calling Parser::parse<FunctionBodyNode>().   
     2596    if (!data())
     2597        scopeChainNode->globalData->parser->reparseInPlace(scopeChainNode->globalData, this);
     2598    ASSERT(data());
     2599
     2600    ScopeChain scopeChain(scopeChainNode);
     2601    JSGlobalObject* globalObject = scopeChain.globalObject();
     2602
     2603    m_code.set(new CodeBlock(this, FunctionCode, source().provider(), source().startOffset()));
     2604
     2605    BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get());
     2606    generator.generate();
     2607
     2608    destroyData();
     2609}
     2610
     2611CodeBlock& FunctionBodyNode::bytecodeForExceptionInfoReparse(ScopeChainNode* scopeChainNode)
     2612{
     2613    ASSERT(!m_code);
     2614
     2615    ScopeChain scopeChain(scopeChainNode);
     2616    JSGlobalObject* globalObject = scopeChain.globalObject();
     2617
     2618    m_code.set(new CodeBlock(this, FunctionCode, source().provider(), source().startOffset()));
     2619
     2620    BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get());
     2621    generator.setRegeneratingForExceptionInfo();
     2622    generator.generate();
     2623
     2624    return *m_code;
     2625}
     2626
     2627RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
     2628{
     2629    generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine());
     2630    statementListEmitCode(children(), generator, generator.ignoredResult());
     2631    if (!children().size() || !children().last()->isReturnNode()) {
     2632        RegisterID* r0 = generator.emitLoad(0, jsUndefined());
     2633        generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine());
     2634        generator.emitReturn(r0);
     2635    }
     2636    return 0;
     2637}
     2638
    26072639UString FunctionBodyNode::paramString() const
    26082640{
Note: See TracChangeset for help on using the changeset viewer.