Ignore:
Timestamp:
Aug 20, 2009, 7:24:49 AM (16 years ago)
Author:
Darin Adler
Message:

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

Patch by Darin Adler <Darin Adler> on 2009-08-20
Reviewed by Gavin Barraclough.

Use an actual arena now. 0.7% speedup on SunSpider.

longer needs to be used outside JavaScriptCore.

Executable.h project-internal instead of "private".

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator): Updated since VarStack
contains const Identifier* now.

  • parser/Grammar.y: Made identifiers from the lexer be const

Identifier* and updated since VarStack contains const Identifier* now.

  • 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::clear): Removed the code to manage m_identifiers 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::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): 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::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 to
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.
(JSC::Parser::parseFunctionFromGlobalCode): Changed to use the
singleStatement function, since there is no longer any children function.
Removed some unneeded use of RefPtr.

  • 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 a separate
IdentifierArena object, a segmented vector of identifiers that used
to be in the Lexer.

  • runtime/Executable.h: Moved the definition of the

FunctionExecutable::make function here. It can't go in JSFunction.h
since that header has to be used outside JavaScriptCore and so can't
include this, which includes Nodes.h. The function could be moved
elswhere if we don't want to include JSFunction.h in this header, but
for now this seems to be the best place.

  • runtime/JSFunction.h: Removed the include of Executable.h and

definition of the FunctionExecutable::make function.

  • wtf/FastMalloc.cpp: Fixed an incorrect comment.
File:
1 edited

Legend:

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

    r47412 r47571  
    5050namespace JSC {
    5151
    52 static void substitute(UString& string, const UString& substring);
     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
     
    123161    if (dst == generator.ignoredResult())
    124162        return 0;
    125     return generator.emitLoad(dst, m_double);
     163    return generator.emitLoad(dst, m_value);
    126164}
    127165
     
    141179    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;
     
    597635RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
    598636{
    599     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.");
     637    return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus
     638        ? "Postfix ++ operator applied to value that is not a reference."
     639        : "Postfix -- operator applied to value that is not a reference.");
    600640}
    601641
     
    759799RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
    760800{
    761     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.");
     801    return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus
     802        ? "Prefix ++ operator applied to value that is not a reference."
     803        : "Prefix -- operator applied to value that is not a reference.");
    762804}
    763805
     
    12371279}
    12381280
    1239 // ------------------------------ Helper functions for handling Vectors of StatementNode -------------------------------
    1240 
    1241 static inline void statementListEmitCode(const StatementVector& statements, BytecodeGenerator& generator, RegisterID* dst)
    1242 {
    1243     size_t size = statements.size();
     1281// ------------------------------ SourceElements -------------------------------
     1282
     1283inline void SourceElements::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
     1284{
     1285    size_t size = m_statements.size();
    12441286    for (size_t i = 0; i < size; ++i)
    1245         generator.emitNode(dst, statements[i]);
     1287        generator.emitNode(dst, m_statements[i]);
    12461288}
    12471289
    12481290// ------------------------------ BlockNode ------------------------------------
    12491291
     1292inline StatementNode* BlockNode::lastStatement() const
     1293{
     1294    return m_statements ? m_statements->lastStatement() : 0;
     1295}
     1296
    12501297RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    12511298{
    1252     statementListEmitCode(m_children, generator, dst);
     1299    if (m_statements)
     1300        m_statements->emitBytecode(generator, dst);
    12531301    return 0;
    12541302}
     
    15501598    generator.emitPopScope();
    15511599    return result;
     1600}
     1601
     1602// ------------------------------ CaseClauseNode --------------------------------
     1603
     1604inline void CaseClauseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
     1605{
     1606    if (m_statements)
     1607        m_statements->emitBytecode(generator, dst);
    15521608}
    15531609
     
    16711727    for (ClauseListNode* list = m_list1; list; list = list->getNext()) {
    16721728        generator.emitLabel(labelVector[i++].get());
    1673         statementListEmitCode(list->getClause()->children(), generator, dst);
     1729        list->getClause()->emitBytecode(generator, dst);
    16741730    }
    16751731
    16761732    if (m_defaultClause) {
    16771733        generator.emitLabel(defaultLabel.get());
    1678         statementListEmitCode(m_defaultClause->children(), generator, dst);
     1734        m_defaultClause->emitBytecode(generator, dst);
    16791735    }
    16801736
    16811737    for (ClauseListNode* list = m_list2; list; list = list->getNext()) {
    16821738        generator.emitLabel(labelVector[i++].get());
    1683         statementListEmitCode(list->getClause()->children(), generator, dst);
     1739        list->getClause()->emitBytecode(generator, dst);
    16841740    }
    16851741    if (!m_defaultClause)
     
    18131869// -----------------------------ScopeNodeData ---------------------------
    18141870
    1815 ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, int numConstants)
     1871ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* statements, VarStack* varStack, FunctionStack* funcStack, int numConstants)
    18161872    : m_numConstants(numConstants)
     1873    , m_statements(statements)
    18171874{
    18181875    m_arena.swap(arena);
     
    18211878    if (funcStack)
    18221879        m_functionStack.swap(*funcStack);
    1823     if (children)
    1824         children->releaseContentsIntoVector(m_children);
    18251880}
    18261881
     
    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
     1914StatementNode* 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());
     
    19061972    RefPtr<RegisterID> dstRegister = generator.newTemporary();
    19071973    generator.emitLoad(dstRegister.get(), jsUndefined());
    1908     statementListEmitCode(children(), generator, dstRegister.get());
     1974    emitStatementsBytecode(generator, dstRegister.get());
    19091975
    19101976    generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine());
     
    19832049{
    19842050    generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine());
    1985     statementListEmitCode(children(), generator, generator.ignoredResult());
    1986     if (children().size() && children().last()->isBlock()) {
    1987         BlockNode* blockNode = static_cast<BlockNode*>(children().last());
    1988         if (blockNode->children().size() && blockNode->children().last()->isReturnNode())
     2051    emitStatementsBytecode(generator, generator.ignoredResult());
     2052    StatementNode* singleStatement = this->singleStatement();
     2053    if (singleStatement && singleStatement->isBlock()) {
     2054        StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement();
     2055        if (lastStatementInBlock && lastStatementInBlock->isReturnNode())
    19892056            return 0;
    19902057    }
Note: See TracChangeset for help on using the changeset viewer.