Ignore:
Timestamp:
May 13, 2009, 11:14:48 AM (16 years ago)
Author:
Darin Adler
Message:

JavaScriptCore:

2009-05-13 Darin Adler <Darin Adler>

Reviewed by Cameron Zwarich.

Bug 25674: syntax tree nodes should use arena allocation
https://bugs.webkit.org/show_bug.cgi?id=25674

Step 3: Add some actual arena allocation. About 1% SunSpider speedup.

  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::BytecodeGenerator): Updated since VarStack contains const Identifier* now. (JSC::BytecodeGenerator::emitPushNewScope): Updated to take a const Identifier&.
  • bytecompiler/BytecodeGenerator.h: Ditto
  • bytecompiler/SegmentedVector.h: Added isEmpty.
  • debugger/Debugger.cpp: (JSC::Debugger::recompileAllJSFunctions): Moved this function here from WebCore so WebCore doesn't need the details of FunctionBodyNode.
  • debugger/Debugger.h: Ditto.
  • interpreter/Interpreter.cpp: (JSC::Interpreter::execute): Updated since VarStack contains const Identifier* now.
  • jit/JITStubs.cpp: (JSC::JITStubs::cti_vm_lazyLinkCall): Call isHostFunction on the body rather than on the function object, since we can't easily have inlined access to the FunctionBodyNode in JSFunction.h since WebCore needs access to that header. (JSC::JITStubs::cti_op_construct_JSConstruct): Ditto.
  • profiler/Profiler.cpp: (JSC::Profiler::createCallIdentifier): Ditto.
  • parser/Grammar.y: Use JSGlobalData* to pass the global data pointer around whenever possible instead of using void*. Changed SET_EXCEPTION_LOCATION from a macro to an inline function. Marked the structure-creating functions inline. Changed the VarStack to use identifier pointers instead of actual identifiers. This takes advantage of the fact that all identifier pointers come from the arena and avoids referenc count churn. Changed Identifier* to const Identifier* to make sure we don't modify any by accident. Used identifiers for regular expression strings too, using the new scanRegExp that has out parameters instead of the old one that relied on side effects in the Lexer. Move the creation of numeric identifiers out of this file and into the PropertyNode constructor.
  • parser/Lexer.cpp: (JSC::Lexer::setCode): Pass in ParserArena, used for identifiers. (JSC::Lexer::makeIdentifier): Changed return type to const Identifier* and changed to call ParserArena. (JSC::Lexer::scanRegExp): Added out arguments that are const Identifier* as well as a prefix character argument so we can handle the /= case without a string append. (JSC::Lexer::skipRegExp): Added. Skips a regular expression without allocating Identifier objects. (JSC::Lexer::clear): Removed the code to manage m_identifiers, m_pattern, and m_flags, and added code to set m_arena to 0.
  • parser/Lexer.h: Updated for changes above.
  • parser/NodeConstructors.h: (JSC::ParserArenaFreeable::operator new): Added. Calls allocateFreeable on the arena. (JSC::ParserArenaDeletable::operator new): Changed to call the allocateDeletable function on the arena instead of deleteWithArena. (JSC::RegExpNode::RegExpNode): Changed arguments to Identifier instead of UString since these come from the parser which makes identifiers. (JSC::PropertyNode::PropertyNode): Added new constructor that makes numeric identifiers. Some day we might want to optimize this for integers so it doesn't create a string for each one. (JSC::ContinueNode::ContinueNode): Initialize m_ident to nullIdentifier since it's now a const Identifier& so it can't be left uninitialized. (JSC::BreakNode::BreakNode): Ditto. (JSC::CaseClauseNode::CaseClauseNode): Updated to use SourceElements* to keep track of the statements rather than a separate statement vector. (JSC::BlockNode::BlockNode): Ditto. (JSC::ForInNode::ForInNode): Initialize m_ident to nullIdentifier.
  • parser/Nodes.cpp: Moved the comment explaining emitBytecode in here. It seemed strangely out of place in the header. (JSC::ThrowableExpressionData::emitThrowError): Added an overload for UString as well as Identifier. (JSC::SourceElements::singleStatement): Added. (JSC::SourceElements::lastStatement): Added. (JSC::RegExpNode::emitBytecode): Updated since the pattern and flags are now Identifier instead of UString. Also changed the throwError code to use the substitution mechanism instead of doing a string append. (JSC::SourceElements::emitBytecode): Added. Replaces the old statementListEmitCode function, since we now keep the SourceElements objects around. (JSC::BlockNode::lastStatement): Added. (JSC::BlockNode::emitBytecode): Changed to use emitBytecode instead of statementListEmitCode. (JSC::CaseClauseNode::emitBytecode): Added. (JSC::CaseBlockNode::emitBytecodeForBlock): Changed to use emitBytecode instead of statementListEmitCode. (JSC::ScopeNodeData::ScopeNodeData): Changed to store the SourceElements* instead of using releaseContentsIntoVector. (JSC::ScopeNode::emitStatementsBytecode): Added. (JSC::ScopeNode::singleStatement): Added. (JSC::ProgramNode::emitBytecode): Call emitStatementsBytecode instead of statementListEmitCode. (JSC::EvalNode::emitBytecode): Ditto. (JSC::EvalNode::generateBytecode): Removed code to clear the children vector. This optimization is no longer possible since everything is in a single arena. (JSC::FunctionBodyNode::emitBytecode): Call emitStatementsBytecode insetad of statementListEmitCode and check for the return node using the new functions.
  • parser/Nodes.h: Changed VarStack to store const Identifier* instead of Identifier and rely on the arena to control lifetime. Added a new ParserArenaFreeable class. Made ParserArenaDeletable inherit from FastAllocBase instead of having its own operator new. Base the Node class on ParserArenaFreeable. Changed the various Node classes to use const Identifier& instead of Identifier to avoid the need to call their destructors and allow them to function as "freeable" in the arena. Removed extraneous JSC_FAST_CALL on definitions of inline functions. Changed ElementNode, PropertyNode, ArgumentsNode, ParameterNode, CaseClauseNode, ClauseListNode, and CaseBlockNode to use ParserArenaFreeable as a base class since they do not descend from Node. Eliminated the StatementVector type and instead have various classes use SourceElements* instead of StatementVector. This prevents those classes from having th use ParserArenaDeletable to make sure the vector destructor is called.
  • parser/Parser.cpp: (JSC::Parser::parse): Pass the arena to the lexer.
  • parser/Parser.h: Added an include of ParserArena.h, which is no longer included by Nodes.h.
  • parser/ParserArena.cpp: (JSC::ParserArena::ParserArena): Added. Initializes the new members, m_freeableMemory, m_freeablePoolEnd, and m_identifiers. (JSC::ParserArena::freeablePool): Added. Computes the pool pointer, since we store only the current pointer and the end of pool pointer. (JSC::ParserArena::deallocateObjects): Added. Contains the common memory-deallocation logic used by both the destructor and the reset function. (JSC::ParserArena::~ParserArena): Changed to call deallocateObjects. (JSC::ParserArena::reset): Ditto. Also added code to zero out the new structures, and switched to use clear() instead of shrink(0) since we don't really reuse arenas. (JSC::ParserArena::makeNumericIdentifier): Added. (JSC::ParserArena::allocateFreeablePool): Added. Used when the pool is empty. (JSC::ParserArena::isEmpty): Added. No longer inline, which is fine since this is used only for assertions at the moment.
  • parser/ParserArena.h: Added an actual arena of "freeable" objects, ones that don't need destructors to be called. Also added the segmented vector of identifiers that used to be in the Lexer.
  • runtime/FunctionConstructor.cpp: (JSC::extractFunctionBody): Use singleStatement function rather than getting at a StatementVector.
  • runtime/FunctionPrototype.cpp: (JSC::functionProtoFuncToString): Call isHostFunction on the body rather than the function object.
  • runtime/JSFunction.cpp: (JSC::JSFunction::JSFunction): Moved the structure version of this in here from the header. It's not hot enough that it needs to be inlined. (JSC::JSFunction::isHostFunction): Moved this in here from the header. It's now a helper to be used only within the class. (JSC::JSFunction::setBody): Moved this in here. It's not hot enough that it needs to be inlined, and we want to be able to compile the header without the definition of FunctionBodyNode.
  • runtime/JSFunction.h: Eliminated the include of "Nodes.h". This was exposing too much JavaScriptCore dependency to WebCore. Because of this change and some changes made to WebCore, we could now export a lot fewer headers from JavaScriptCore, but I have not done that yet in this check-in. Made a couple functions non-inline. Removes some isHostFunction() assertions.


  • wtf/FastAllocBase.h: Added the conventional using statements we use in WTF so we can use identifiers from the WTF namespace without explicit namespace qualification or namespace directive. This is the usual WTF style, although it's unconventional in the C++ world. We use the namespace primarily for link-time disambiguation, not compile-time.
  • wtf/FastMalloc.cpp: Fixed an incorrect comment.

WebCore:

2009-05-13 Darin Adler <Darin Adler>

Reviewed by Cameron Zwarich.

Bug 25674: syntax tree nodes should use arena allocation
https://bugs.webkit.org/show_bug.cgi?id=25674

  • bindings/js/JSDOMBinding.h: Removed include of JSFunction.h. We don't want the entire DOM binding to depend on that file.
  • bindings/js/JSAudioConstructor.cpp: Added include of Error.h. Before we inherited this automatically because JDDOMBinding.h included JSFunction.h, but that was excessive.
  • bindings/js/JSDOMWindowCustom.cpp: Ditto.
  • bindings/js/JSHTMLInputElementCustom.cpp: Ditto.
  • bindings/js/JSImageConstructor.cpp: Ditto.
  • bindings/js/JSLazyEventListener.cpp: Ditto, but for JSFunction.h.
  • bindings/js/JSMessageChannelConstructor.cpp: Ditto.
  • bindings/js/JSOptionConstructor.cpp: Ditto.
  • bindings/js/JSWorkerConstructor.cpp: Ditto.
  • bindings/js/JSXMLHttpRequestConstructor.cpp: Ditto.
  • bridge/jni/jni_jsobject.mm: Ditto, but for SourceCode.h.
  • inspector/InspectorController.cpp: Ditto.
  • inspector/JavaScriptDebugServer.cpp: (WebCore::JavaScriptDebugServer::recompileAllJSFunctions): Moved mose of this function into the base class in JavaScriptCore, so the details of compilation don't have to be exposed.

WebKit/mac:

2009-05-13 Darin Adler <Darin Adler>

Reviewed by Cameron Zwarich.

Bug 25674: syntax tree nodes should use arena allocation
https://bugs.webkit.org/show_bug.cgi?id=25674

  • Plugins/Hosted/NetscapePluginInstanceProxy.mm: Updated includes. New ones needed due to reducing includes of JSDOMBinding.h.
  • WebView/WebScriptDebugger.mm: Ditto.
File:
1 edited

Legend:

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

    r43619 r43642  
    5050namespace JSC {
    5151
    52 static void substitute(UString& string, const UString& substring) JSC_FAST_CALL;
     52/*
     53    Details of the emitBytecode function.
     54
     55    Return value: The register holding the production's value.
     56             dst: An optional parameter specifying the most efficient destination at
     57                  which to store the production's value. The callee must honor dst.
     58
     59    The dst argument provides for a crude form of copy propagation. For example,
     60
     61        x = 1
     62
     63    becomes
     64   
     65        load r[x], 1
     66   
     67    instead of
     68
     69        load r0, 1
     70        mov r[x], r0
     71   
     72    because the assignment node, "x =", passes r[x] as dst to the number node, "1".
     73*/
    5374
    5475// ------------------------------ ThrowableExpressionData --------------------------------
     
    6485}
    6586
    66 RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType e, const char* msg)
     87RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* message)
    6788{
    6889    generator.emitExpressionInfo(divot(), startOffset(), endOffset());
    69     RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), msg));
     90    RegisterID* exception = generator.emitNewError(generator.newTemporary(), type, jsString(generator.globalData(), message));
    7091    generator.emitThrow(exception);
    7192    return exception;
    7293}
    7394
    74 RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType e, const char* msg, const Identifier& label)
    75 {
    76     UString message = msg;
    77     substitute(message, label.ustring());
     95RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const UString& label)
     96{
     97    UString message = messageTemplate;
     98    substitute(message, label);
    7899    generator.emitExpressionInfo(divot(), startOffset(), endOffset());
    79     RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), message));
     100    RegisterID* exception = generator.emitNewError(generator.newTemporary(), type, jsString(generator.globalData(), message));
    80101    generator.emitThrow(exception);
    81102    return exception;
     103}
     104
     105inline RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const Identifier& label)
     106{
     107    return emitThrowError(generator, type, messageTemplate, label.ustring());
    82108}
    83109
     
    99125}
    100126
     127inline StatementNode* SourceElements::singleStatement() const
     128{
     129    size_t size = m_statements.size();
     130    return size == 1 ? m_statements[0] : 0;
     131}
     132
     133inline StatementNode* SourceElements::lastStatement() const
     134{
     135    size_t size = m_statements.size();
     136    return size ? m_statements[size - 1] : 0;
     137}
     138
    101139// ------------------------------ NullNode -------------------------------------
    102140
     
    139177RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    140178{
    141     RefPtr<RegExp> regExp = RegExp::create(generator.globalData(), m_pattern, m_flags);
     179    RefPtr<RegExp> regExp = RegExp::create(generator.globalData(), m_pattern.ustring(), m_flags.ustring());
    142180    if (!regExp->isValid())
    143         return emitThrowError(generator, SyntaxError, ("Invalid regular expression: " + UString(regExp->errorMessage())).UTF8String().c_str());
     181        return emitThrowError(generator, SyntaxError, "Invalid regular expression: %s", regExp->errorMessage());
    144182    if (dst == generator.ignoredResult())
    145183        return 0;
     
    593631RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
    594632{
    595     return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Postfix ++ operator applied to value that is not a reference." : "Postfix -- operator applied to value that is not a reference.");
     633    return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus
     634        ? "Postfix ++ operator applied to value that is not a reference."
     635        : "Postfix -- operator applied to value that is not a reference.");
    596636}
    597637
     
    755795RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
    756796{
    757     return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Prefix ++ operator applied to value that is not a reference." : "Prefix -- operator applied to value that is not a reference.");
     797    return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus
     798        ? "Prefix ++ operator applied to value that is not a reference."
     799        : "Prefix -- operator applied to value that is not a reference.");
    758800}
    759801
     
    12251267}
    12261268
    1227 // ------------------------------ Helper functions for handling Vectors of StatementNode -------------------------------
    1228 
    1229 static inline void statementListEmitCode(const StatementVector& statements, BytecodeGenerator& generator, RegisterID* dst)
    1230 {
    1231     size_t size = statements.size();
     1269// ------------------------------ SourceElements -------------------------------
     1270
     1271inline void SourceElements::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
     1272{
     1273    size_t size = m_statements.size();
    12321274    for (size_t i = 0; i < size; ++i)
    1233         generator.emitNode(dst, statements[i]);
     1275        generator.emitNode(dst, m_statements[i]);
    12341276}
    12351277
    12361278// ------------------------------ BlockNode ------------------------------------
    12371279
     1280inline StatementNode* BlockNode::lastStatement() const
     1281{
     1282    return m_statements ? m_statements->lastStatement() : 0;
     1283}
     1284
    12381285RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    12391286{
    1240     statementListEmitCode(m_children, generator, dst);
     1287    if (m_statements)
     1288        m_statements->emitBytecode(generator, dst);
    12411289    return 0;
    12421290}
     
    15411589    generator.emitPopScope();
    15421590    return result;
     1591}
     1592
     1593// ------------------------------ CaseClauseNode --------------------------------
     1594
     1595inline void CaseClauseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
     1596{
     1597    if (m_statements)
     1598        m_statements->emitBytecode(generator, dst);
    15431599}
    15441600
     
    16641720    for (ClauseListNode* list = m_list1; list; list = list->getNext()) {
    16651721        generator.emitLabel(labelVector[i++].get());
    1666         statementListEmitCode(list->getClause()->children(), generator, dst);
     1722        list->getClause()->emitBytecode(generator, dst);
    16671723    }
    16681724
    16691725    if (m_defaultClause) {
    16701726        generator.emitLabel(defaultLabel.get());
    1671         statementListEmitCode(m_defaultClause->children(), generator, dst);
     1727        m_defaultClause->emitBytecode(generator, dst);
    16721728    }
    16731729
    16741730    for (ClauseListNode* list = m_list2; list; list = list->getNext()) {
    16751731        generator.emitLabel(labelVector[i++].get());
    1676         statementListEmitCode(list->getClause()->children(), generator, dst);
     1732        list->getClause()->emitBytecode(generator, dst);
    16771733    }
    16781734    if (!m_defaultClause)
     
    18021858// -----------------------------ScopeNodeData ---------------------------
    18031859
    1804 ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, int numConstants)
     1860ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* statements, VarStack* varStack, FunctionStack* funcStack, int numConstants)
    18051861    : m_numConstants(numConstants)
     1862    , m_statements(statements)
    18061863{
    18071864    m_arena.swap(arena);
     
    18101867    if (funcStack)
    18111868        m_functionStack.swap(*funcStack);
    1812     if (children)
    1813         children->releaseContentsIntoVector(m_children);
    18141869}
    18151870
     
    18511906}
    18521907
     1908inline void ScopeNode::emitStatementsBytecode(BytecodeGenerator& generator, RegisterID* dst)
     1909{
     1910    if (m_data->m_statements)
     1911        m_data->m_statements->emitBytecode(generator, dst);
     1912}
     1913
     1914inline StatementNode* ScopeNode::singleStatement() const
     1915{
     1916    return m_data->m_statements ? m_data->m_statements->singleStatement() : 0;
     1917}
     1918
    18531919// ------------------------------ ProgramNode -----------------------------
    18541920
     
    18751941    RefPtr<RegisterID> dstRegister = generator.newTemporary();
    18761942    generator.emitLoad(dstRegister.get(), jsUndefined());
    1877     statementListEmitCode(children(), generator, dstRegister.get());
     1943    emitStatementsBytecode(generator, dstRegister.get());
    18781944
    18791945    generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine());
     
    19191985    RefPtr<RegisterID> dstRegister = generator.newTemporary();
    19201986    generator.emitLoad(dstRegister.get(), jsUndefined());
    1921     statementListEmitCode(children(), generator, dstRegister.get());
     1987    emitStatementsBytecode(generator, dstRegister.get());
    19221988
    19231989    generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine());
     
    19372003
    19382004    // Eval code needs to hang on to its declaration stacks to keep declaration info alive until Interpreter::execute time,
    1939     // so the entire ScopeNodeData cannot be destoyed.
    1940     children().clear();
     2005    // so the ScopeNodeData cannot be destroyed at this point. Maybe we can destroy part of it in the future?
    19412006}
    19422007
     
    20922157{
    20932158    generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine());
    2094     statementListEmitCode(children(), generator, generator.ignoredResult());
    2095     if (children().size() && children().last()->isBlock()) {
    2096         BlockNode* blockNode = static_cast<BlockNode*>(children().last());
    2097         if (blockNode->children().size() && blockNode->children().last()->isReturnNode())
     2159    emitStatementsBytecode(generator, generator.ignoredResult());
     2160    StatementNode* singleStatement = this->singleStatement();
     2161    if (singleStatement && singleStatement->isBlock()) {
     2162        StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement();
     2163        if (lastStatementInBlock && lastStatementInBlock->isReturnNode())
    20982164            return 0;
    20992165    }
Note: See TracChangeset for help on using the changeset viewer.