Commit 53ecc4e3 authored by darin@apple.com's avatar darin@apple.com

JavaScriptCore:

2009-05-13  Darin Adler  <darin@apple.com>

        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.

        * JavaScriptCore.exp: Updated.

        * 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@apple.com>

        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@apple.com>

        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.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@43642 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 7f496054
This diff is collapsed.
......@@ -149,7 +149,6 @@ __ZN3JSC15JSWrapperObject4markEv
__ZN3JSC15toInt32SlowCaseEdRb
__ZN3JSC16FunctionBodyNode13finishParsingEPNS_10IdentifierEm
__ZN3JSC16FunctionBodyNode14copyParametersEv
__ZN3JSC16FunctionBodyNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairINS_10IdentifierEjELm0EEEPNS6_IPNS_12FuncDeclNodeELm0EEERKNS_10SourceCodeEji
__ZN3JSC16InternalFunction4infoE
__ZN3JSC16InternalFunction4nameEPNS_12JSGlobalDataE
__ZN3JSC16InternalFunctionC2EPNS_12JSGlobalDataEN3WTF10PassRefPtrINS_9StructureEEERKNS_10IdentifierE
......@@ -228,6 +227,7 @@ __ZN3JSC7UString6appendERKS0_
__ZN3JSC7UStringC1EPKc
__ZN3JSC7UStringC1EPKti
__ZN3JSC7UStringaSEPKc
__ZN3JSC8Debugger23recompileAllJSFunctionsEPNS_12JSGlobalDataEb
__ZN3JSC8Debugger6attachEPNS_14JSGlobalObjectE
__ZN3JSC8Debugger6detachEPNS_14JSGlobalObjectE
__ZN3JSC8DebuggerC2Ev
......@@ -302,6 +302,7 @@ __ZN3WTF21RefCountedLeakCounter9incrementEv
__ZN3WTF21RefCountedLeakCounterC1EPKc
__ZN3WTF21RefCountedLeakCounterD1Ev
__ZN3WTF23waitForThreadCompletionENS_16ThreadIdentifierEPPv
__ZN3WTF23waitForThreadCompletionEjPPv
__ZN3WTF27releaseFastMallocFreeMemoryEv
__ZN3WTF28setMainThreadCallbacksPausedEb
__ZN3WTF36lockAtomicallyInitializedStaticMutexEv
......@@ -362,9 +363,9 @@ __ZNK3JSC8JSObject9classNameEv
__ZNK3JSC8JSObject9toBooleanEPNS_9ExecStateE
__ZNK3JSC9HashTable11createTableEPNS_12JSGlobalDataE
__ZNK3JSC9HashTable11deleteTableEv
__ZNK3WTF8Collator7collateEPKtmS2_m
__ZNK3WTF16ThreadIdentifiereqERKS0_
__ZNK3WTF16ThreadIdentifierneERKS0_
__ZNK3WTF8Collator7collateEPKtmS2_m
__ZTVN3JSC12StringObjectE
__ZTVN3JSC14JSGlobalObjectE
__ZTVN3JSC15JSWrapperObjectE
......@@ -374,4 +375,3 @@ __ZTVN3JSC8JSObjectE
__ZTVN3JSC8JSStringE
_jscore_fastmalloc_introspection
_kJSClassDefinitionEmpty
__ZN3WTF23waitForThreadCompletionEjPPv
......@@ -269,8 +269,8 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* d
Vector<RegisterID*, 32> newVars;
for (size_t i = 0; i < varStack.size(); ++i)
if (!globalObject->hasProperty(exec, varStack[i].first))
newVars.append(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant));
if (!globalObject->hasProperty(exec, *varStack[i].first))
newVars.append(addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant));
allocateConstants(programNode->neededConstants());
......@@ -282,12 +282,12 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* d
globalObject->putWithAttributes(exec, funcDecl->m_ident, funcDecl->makeFunction(exec, scopeChain.node()), DontDelete);
}
for (size_t i = 0; i < varStack.size(); ++i) {
if (globalObject->hasProperty(exec, varStack[i].first))
if (globalObject->hasProperty(exec, *varStack[i].first))
continue;
int attributes = DontDelete;
if (varStack[i].second & DeclarationStacks::IsConstant)
attributes |= ReadOnly;
globalObject->putWithAttributes(exec, varStack[i].first, jsUndefined(), attributes);
globalObject->putWithAttributes(exec, *varStack[i].first, jsUndefined(), attributes);
}
allocateConstants(programNode->neededConstants());
......@@ -345,7 +345,7 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug
const DeclarationStacks::VarStack& varStack = functionBody->varStack();
for (size_t i = 0; i < varStack.size(); ++i)
addVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant);
addVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant);
const Identifier* parameters = functionBody->parameters();
size_t parameterCount = functionBody->parameterCount();
......@@ -1837,7 +1837,7 @@ void BytecodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc)
instructions().append(retAddrSrc->index());
}
void BytecodeGenerator::emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value)
void BytecodeGenerator::emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value)
{
ControlFlowContext context;
context.isFinallyBlock = false;
......
......@@ -319,7 +319,7 @@ namespace JSC {
RegisterID* emitCatch(RegisterID*, Label* start, Label* end);
void emitThrow(RegisterID* exc) { emitUnaryNoDstOp(op_throw, exc); }
RegisterID* emitNewError(RegisterID* dst, ErrorType type, JSValue message);
void emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value);
void emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value);
RegisterID* emitPushScope(RegisterID* scope);
void emitPopScope();
......
......@@ -50,6 +50,7 @@ namespace JSC {
}
size_t size() const { return m_size; }
bool isEmpty() const { return !size(); }
T& at(size_t index)
{
......
......@@ -22,8 +22,9 @@
#include "config.h"
#include "Debugger.h"
#include "JSGlobalObject.h"
#include "CollectorHeapIterator.h"
#include "Interpreter.h"
#include "JSGlobalObject.h"
#include "Parser.h"
namespace JSC {
......@@ -53,6 +54,63 @@ void Debugger::detach(JSGlobalObject* globalObject)
globalObject->setDebugger(0);
}
void Debugger::recompileAllJSFunctions(JSGlobalData* globalData, bool callSourceParsed)
{
// If JavaScript is running, it's not safe to recompile, since we'll end
// up throwing away code that is live on the stack.
ASSERT(!globalData->dynamicGlobalObject);
if (globalData->dynamicGlobalObject)
return;
Vector<ProtectedPtr<JSFunction> > functions;
Heap::iterator heapEnd = globalData->heap.primaryHeapEnd();
for (Heap::iterator it = globalData->heap.primaryHeapBegin(); it != heapEnd; ++it) {
if ((*it)->isObject(&JSFunction::info)) {
JSFunction* function = static_cast<JSFunction*>(*it);
FunctionBodyNode* body = function->body();
if (body && !body->isHostFunction())
functions.append(function);
}
}
typedef HashMap<RefPtr<FunctionBodyNode>, RefPtr<FunctionBodyNode> > FunctionBodyMap;
typedef HashMap<SourceProvider*, ExecState*> SourceProviderMap;
FunctionBodyMap functionBodies;
SourceProviderMap sourceProviders;
size_t size = functions.size();
for (size_t i = 0; i < size; ++i) {
JSFunction* function = functions[i];
FunctionBodyNode* oldBody = function->body();
pair<FunctionBodyMap::iterator, bool> result = functionBodies.add(oldBody, 0);
if (!result.second) {
function->setBody(result.first->second.get());
continue;
}
ExecState* exec = function->scope().globalObject()->JSGlobalObject::globalExec();
const SourceCode& sourceCode = oldBody->source();
RefPtr<FunctionBodyNode> newBody = globalData->parser->parse<FunctionBodyNode>(exec, 0, sourceCode);
ASSERT(newBody);
newBody->finishParsing(oldBody->copyParameters(), oldBody->parameterCount());
result.first->second = newBody;
function->setBody(newBody.release());
if (callSourceParsed && function->scope().globalObject()->debugger() == this)
sourceProviders.add(sourceCode.provider(), exec);
}
// Call sourceParsed() after reparsing all functions because it will execute
// JavaScript in the inspector.
SourceProviderMap::const_iterator end = sourceProviders.end();
for (SourceProviderMap::const_iterator iter = sourceProviders.begin(); iter != end; ++iter)
sourceParsed((*iter).second, SourceCode((*iter).first), -1, 0);
}
JSValue evaluateInGlobalCallFrame(const UString& script, JSValue& exception, JSGlobalObject* globalObject)
{
CallFrame* globalCallFrame = globalObject->globalExec();
......
......@@ -50,6 +50,8 @@ namespace JSC {
virtual void didExecuteProgram(const DebuggerCallFrame&, intptr_t sourceID, int lineno) = 0;
virtual void didReachBreakpoint(const DebuggerCallFrame&, intptr_t sourceID, int lineno) = 0;
void recompileAllJSFunctions(JSGlobalData*, bool callSourceParsed);
private:
HashSet<JSGlobalObject*> m_globalObjects;
};
......
......@@ -826,7 +826,7 @@ JSValue Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject*
const DeclarationStacks::VarStack& varStack = codeBlock->ownerNode()->varStack();
DeclarationStacks::VarStack::const_iterator varStackEnd = varStack.end();
for (DeclarationStacks::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
const Identifier& ident = (*it).first;
const Identifier& ident = *it->first;
if (!variableObject->hasProperty(callFrame, ident)) {
PutPropertySlot slot;
variableObject->put(callFrame, ident, jsUndefined(), slot);
......
......@@ -1046,12 +1046,13 @@ void* JITStubs::cti_vm_lazyLinkCall(STUB_ARGS_DECLARATION)
STUB_INIT_STACK_FRAME(stackFrame);
JSFunction* callee = asFunction(stackFrame.args[0].jsValue());
JITCode jitCode = callee->body()->generatedJITCode();
FunctionBodyNode* calleeBody = callee->body();
JITCode jitCode = calleeBody->generatedJITCode();
ASSERT(jitCode);
CodeBlock* codeBlock = 0;
if (!callee->isHostFunction())
codeBlock = &callee->body()->bytecode(callee->scope().node());
if (!calleeBody->isHostFunction())
codeBlock = &calleeBody->bytecode(callee->scope().node());
CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(stackFrame.args[1].returnAddress());
JIT::linkCall(callee, codeBlock, jitCode, callLinkInfo, stackFrame.args[2].int32());
......@@ -1217,7 +1218,8 @@ JSObject* JITStubs::cti_op_construct_JSConstruct(STUB_ARGS_DECLARATION)
STUB_INIT_STACK_FRAME(stackFrame);
JSFunction* constructor = asFunction(stackFrame.args[0].jsValue());
if (constructor->isHostFunction()) {
FunctionBodyNode* constructorBody = constructor->body();
if (UNLIKELY(constructorBody && constructorBody->isHostFunction())) {
CallFrame* callFrame = stackFrame.callFrame;
CodeBlock* codeBlock = callFrame->codeBlock();
unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
......
This diff is collapsed.
......@@ -141,8 +141,10 @@ ALWAYS_INLINE void Lexer::shift4()
m_code += 4;
}
void Lexer::setCode(const SourceCode& source)
void Lexer::setCode(const SourceCode& source, ParserArena& arena)
{
m_arena = &arena.identifierArena();
m_lineNumber = source.firstLine();
m_delimited = false;
m_lastToken = -1;
......@@ -204,10 +206,9 @@ void Lexer::shiftLineTerminator()
++m_lineNumber;
}
ALWAYS_INLINE Identifier* Lexer::makeIdentifier(const UChar* characters, size_t length)
ALWAYS_INLINE const Identifier* Lexer::makeIdentifier(const UChar* characters, size_t length)
{
m_identifiers.append(Identifier(m_globalData, characters, length));
return &m_identifiers.last();
return &JSC::makeIdentifier(*m_arena, m_globalData, characters, length);
}
inline bool Lexer::lastTokenWasRestrKeyword() const
......@@ -908,16 +909,21 @@ returnError:
return -1;
}
bool Lexer::scanRegExp()
bool Lexer::scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar prefix)
{
ASSERT(m_buffer16.isEmpty());
bool lastWasEscape = false;
bool inBrackets = false;
if (prefix)
record16(prefix);
while (true) {
if (isLineTerminator(m_current) || m_current == -1)
if (isLineTerminator(m_current) || m_current == -1) {
m_buffer16.resize(0);
return false;
}
if (m_current != '/' || lastWasEscape || inBrackets) {
// keep track of '[' and ']'
if (!lastWasEscape) {
......@@ -929,7 +935,7 @@ bool Lexer::scanRegExp()
record16(m_current);
lastWasEscape = !lastWasEscape && m_current == '\\';
} else { // end of regexp
m_pattern = UString(m_buffer16);
pattern = makeIdentifier(m_buffer16.data(), m_buffer16.size());
m_buffer16.resize(0);
shift1();
break;
......@@ -941,15 +947,45 @@ bool Lexer::scanRegExp()
record16(m_current);
shift1();
}
m_flags = UString(m_buffer16);
flags = makeIdentifier(m_buffer16.data(), m_buffer16.size());
m_buffer16.resize(0);
return true;
}
bool Lexer::skipRegExp()
{
bool lastWasEscape = false;
bool inBrackets = false;
while (true) {
if (isLineTerminator(m_current) || m_current == -1)
return false;
if (m_current != '/' || lastWasEscape || inBrackets) {
// keep track of '[' and ']'
if (!lastWasEscape) {
if (m_current == '[' && !inBrackets)
inBrackets = true;
if (m_current == ']' && inBrackets)
inBrackets = false;
}
lastWasEscape = !lastWasEscape && m_current == '\\';
} else { // end of regexp
shift1();
break;
}
shift1();
}
while (isIdentPart(m_current))
shift1();
return true;
}
void Lexer::clear()
{
m_identifiers.clear();
m_arena = 0;
m_codeWithoutBOMs.clear();
Vector<char> newBuffer8;
......@@ -961,9 +997,6 @@ void Lexer::clear()
m_buffer16.swap(newBuffer16);
m_isReparsing = false;
m_pattern = UString();
m_flags = UString();
}
SourceCode Lexer::sourceCode(int openBrace, int closeBrace, int firstLine)
......
......@@ -23,7 +23,7 @@
#define Lexer_h
#include "Lookup.h"
#include "SegmentedVector.h"
#include "ParserArena.h"
#include "SourceCode.h"
#include <wtf/ASCIICType.h>
#include <wtf/Vector.h>
......@@ -42,7 +42,7 @@ namespace JSC {
static UChar convertUnicode(int c1, int c2, int c3, int c4);
// Functions to set up parsing.
void setCode(const SourceCode&);
void setCode(const SourceCode&, ParserArena&);
void setIsReparsing() { m_isReparsing = true; }
// Functions for the parser itself.
......@@ -50,9 +50,8 @@ namespace JSC {
int lineNumber() const { return m_lineNumber; }
bool prevTerminator() const { return m_terminator; }
SourceCode sourceCode(int openBrace, int closeBrace, int firstLine);
bool scanRegExp();
const UString& pattern() const { return m_pattern; }
const UString& flags() const { return m_flags; }
bool scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar prefix = 0);
bool skipRegExp();
// Functions for use after parsing.
bool sawError() const { return m_error; }
......@@ -79,12 +78,11 @@ namespace JSC {
int currentOffset() const;
const UChar* currentCharacter() const;
JSC::Identifier* makeIdentifier(const UChar* buffer, size_t length);
const Identifier* makeIdentifier(const UChar* characters, size_t length);
bool lastTokenWasRestrKeyword() const;
static const size_t initialReadBufferCapacity = 32;
static const size_t initialIdentifierTableCapacity = 64;
int m_lineNumber;
......@@ -108,13 +106,10 @@ namespace JSC {
int m_next2;
int m_next3;
SegmentedVector<JSC::Identifier, initialIdentifierTableCapacity> m_identifiers;
IdentifierArena* m_arena;
JSGlobalData* m_globalData;
UString m_pattern;
UString m_flags;
const HashTable m_keywordTable;
Vector<UChar> m_codeWithoutBOMs;
......
......@@ -27,16 +27,14 @@
namespace JSC {
inline void* ParserArenaDeletable::operator new(size_t size, JSGlobalData* globalData)
inline void* ParserArenaFreeable::operator new(size_t size, JSGlobalData* globalData)
{
ParserArenaDeletable* deletable = static_cast<ParserArenaDeletable*>(fastMalloc(size));
globalData->parser->arena().deleteWithArena(deletable);
return deletable;
return globalData->parser->arena().allocateFreeable(size);
}
inline void* ParserArenaDeletable::operator new(size_t size)
inline void* ParserArenaDeletable::operator new(size_t size, JSGlobalData* globalData)
{
return fastMalloc(size);
return globalData->parser->arena().allocateDeletable(size);
}
inline ParserArenaRefCounted::ParserArenaRefCounted(JSGlobalData* globalData)
......@@ -78,13 +76,13 @@ namespace JSC {
{
}
inline StringNode::StringNode(JSGlobalData* globalData, const Identifier& v)
inline StringNode::StringNode(JSGlobalData* globalData, const Identifier& value)
: ExpressionNode(globalData, ResultType::stringType())
, m_value(v)
, m_value(value)
{
}
inline RegExpNode::RegExpNode(JSGlobalData* globalData, const UString& pattern, const UString& flags)
inline RegExpNode::RegExpNode(JSGlobalData* globalData, const Identifier& pattern, const Identifier& flags)
: ExpressionNode(globalData)
, m_pattern(pattern)
, m_flags(flags)
......@@ -149,6 +147,13 @@ namespace JSC {
{
}
inline PropertyNode::PropertyNode(JSGlobalData* globalData, double name, ExpressionNode* assign, Type type)
: m_name(globalData->parser->arena().makeNumericIdentifier(globalData, name))
, m_assign(assign)
, m_type(type)
{
}
inline PropertyListNode::PropertyListNode(JSGlobalData* globalData, PropertyNode* node)
: Node(globalData)
, m_node(node)
......@@ -736,6 +741,7 @@ namespace JSC {
inline ContinueNode::ContinueNode(JSGlobalData* globalData)
: StatementNode(globalData)
, m_ident(globalData->propertyNames->nullIdentifier)
{
}
......@@ -747,6 +753,7 @@ namespace JSC {
inline BreakNode::BreakNode(JSGlobalData* globalData)
: StatementNode(globalData)
, m_ident(globalData->propertyNames->nullIdentifier)
{
}
......@@ -825,16 +832,10 @@ namespace JSC {
m_body->finishParsing(source, parameter);
}
inline CaseClauseNode::CaseClauseNode(JSGlobalData*, ExpressionNode* expr)
: m_expr(expr)
{
}
inline CaseClauseNode::CaseClauseNode(JSGlobalData*, ExpressionNode* expr, SourceElements* children)
inline CaseClauseNode::CaseClauseNode(JSGlobalData*, ExpressionNode* expr, SourceElements* statements)
: m_expr(expr)
, m_statements(statements)
{
if (children)
children->releaseContentsIntoVector(m_children);
}
inline ClauseListNode::ClauseListNode(JSGlobalData*, CaseClauseNode* clause)
......@@ -872,15 +873,15 @@ namespace JSC {
{
}
inline BlockNode::BlockNode(JSGlobalData* globalData, SourceElements* children)
inline BlockNode::BlockNode(JSGlobalData* globalData, SourceElements* statements)
: StatementNode(globalData)
, m_statements(statements)
{
if (children)
children->releaseContentsIntoVector(m_children);
}
inline ForInNode::ForInNode(JSGlobalData* globalData, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
: StatementNode(globalData)
, m_ident(globalData->propertyNames->nullIdentifier)
, m_init(0)
, m_lexpr(l)
, m_expr(expr)
......
This diff is collapsed.
This diff is collapsed.
......@@ -53,7 +53,7 @@ void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg)
*errMsg = 0;
Lexer& lexer = *globalData->lexer;
lexer.setCode(*m_source);
lexer.setCode(*m_source, m_arena);
int parseError = jscyyparse(globalData);
bool lexError = lexer.sawError();
......
......@@ -25,6 +25,7 @@
#include "Debugger.h"
#include "Nodes.h"
#include "ParserArena.h"
#include "SourceProvider.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
......
......@@ -30,9 +30,39 @@
namespace JSC {
ParserArena::ParserArena()
: m_freeableMemory(0)
, m_freeablePoolEnd(0)
, m_identifierArena(new IdentifierArena)
{
}
inline void* ParserArena::freeablePool()
{
ASSERT(m_freeablePoolEnd);
return m_freeablePoolEnd - freeablePoolSize;
}
inline void ParserArena::deallocateObjects()
{
if (m_freeablePoolEnd)
fastFree(freeablePool());
size_t size = m_freeablePools.size();
for (size_t i = 0; i < size; ++i)
fastFree(m_freeablePools[i]);
size = m_deletableObjects.size();
for (size_t i = 0; i < size; ++i) {
ParserArenaDeletable* object = m_deletableObjects[i];
object->~ParserArenaDeletable();
fastFree(object);
}
}
ParserArena::~ParserArena()
{
deleteAllValues(m_deletableObjects);
deallocateObjects();
}
bool ParserArena::contains(ParserArenaRefCounted* object) const
......@@ -52,9 +82,44 @@ void ParserArena::removeLast()
void ParserArena::reset()
{
deleteAllValues(m_deletableObjects);
m_deletableObjects.shrink(0);
m_refCountedObjects.shrink(0);
// Since this code path is used only when parsing fails, it's not bothering to reuse
// any of the memory the arena allocated. We could improve that later if we want to
// efficiently reuse the same arena.
deallocateObjects();
m_freeableMemory = 0;
m_freeablePoolEnd = 0;
m_identifierArena->clear();
m_freeablePools.clear();
m_deletableObjects.clear();
m_refCountedObjects.clear();
}
const Identifier& ParserArena::makeNumericIdentifier(JSGlobalData* globalData, double number)
{
m_identifierArena->append(Identifier(globalData, UString::from(number)));
return m_identifierArena->last();
}
void ParserArena::allocateFreeablePool()
{
if (m_freeablePoolEnd)
m_freeablePools.append(freeablePool());
char* pool = static_cast<char*>(fastMalloc(freeablePoolSize));
m_freeableMemory = pool;
m_freeablePoolEnd = pool + freeablePoolSize;
ASSERT(freeablePool() == pool);
}
bool ParserArena::isEmpty() const
{
return !m_freeablePoolEnd
&& m_identifierArena->isEmpty()
&& m_freeablePools.isEmpty()
&& m_deletableObjects.isEmpty()