From 484648a5c08eaf0f8a9447651f339921797f30d6 Mon Sep 17 00:00:00 2001 From: "ggaren@apple.com" Date: Fri, 16 Nov 2007 06:54:09 +0000 Subject: [PATCH] Reviewed by Eric Seidel. Another round of grammar / parsing cleanup. 1. Created distinct parser calls for parsing function bodies vs programs. This will help later with optimizing global variable access. 2. Turned Parser into a singleton. Cleaned up Lexer's singleton interface. 3. Modified Lexer to free a little more memory when done lexing. (Added FIXMEs for similar issues that I didn't fix.) 4. Changed Lexer::makeIdentifier and Lexer::makeUString to start respecting the arguments passed to them. (No behavior change, but this problem could have caused serious problems for an unsuspecting user of these functions.) 5. Removed KJS_DEBUG_MEM because it was bit-rotted. 6. Removed Parser::prettyPrint because the same work was simpler to do at the call site. 7. Some renames: "Parser::accept" => "Parser::didFinishParsing" "Parser::sid" => "Parser::m_sourceID" "Lexer::doneParsing" => "Lexer::clear" "sid" => "sourceId" "lineno" => "lineNo" * JavaScriptCore.exp: * kjs/Parser.cpp: (KJS::Parser::Parser): (KJS::Parser::parseProgram): (KJS::Parser::parseFunctionBody): (KJS::Parser::parse): (KJS::Parser::didFinishParsing): (KJS::parser): * kjs/Parser.h: (KJS::Parser::sourceId): * kjs/function.cpp: (KJS::GlobalFuncImp::callAsFunction): * kjs/function_object.cpp: (FunctionObjectImp::construct): * kjs/grammar.y: * kjs/interpreter.cpp: (KJS::Interpreter::checkSyntax): (KJS::Interpreter::evaluate): * kjs/interpreter.h: * kjs/lexer.cpp: (kjsyylex): (KJS::lexer): (KJS::Lexer::Lexer): (KJS::Lexer::~Lexer): (KJS::Lexer::scanRegExp): (KJS::Lexer::doneParsing): (KJS::Lexer::makeIdentifier): (KJS::Lexer::makeUString): * kjs/lexer.h: (KJS::Lexer::pattern): (KJS::Lexer::flags): (KJS::Lexer::sawError): * kjs/nodes.cpp: (KJS::Node::Node): (KJS::FunctionBodyNode::FunctionBodyNode): * kjs/nodes.h: * kjs/testkjs.cpp: (prettyPrintScript): (kjsmain): * kjs/ustring.cpp: * kjs/ustring.h: git-svn-id: https://svn.webkit.org/repository/webkit/trunk@27842 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- JavaScriptCore/ChangeLog | 75 ++++++++++++++++++++++++++ JavaScriptCore/JavaScriptCore.exp | 7 ++- JavaScriptCore/kjs/Parser.cpp | 74 +++++++++++++------------ JavaScriptCore/kjs/Parser.h | 41 ++++++++------ JavaScriptCore/kjs/function.cpp | 22 ++++---- JavaScriptCore/kjs/function_object.cpp | 17 +++--- JavaScriptCore/kjs/grammar.y | 23 ++++---- JavaScriptCore/kjs/interpreter.cpp | 24 ++------- JavaScriptCore/kjs/interpreter.h | 7 --- JavaScriptCore/kjs/lexer.cpp | 64 ++++++++++------------ JavaScriptCore/kjs/lexer.h | 67 +++++++++++------------ JavaScriptCore/kjs/nodes.cpp | 8 +-- JavaScriptCore/kjs/nodes.h | 1 + JavaScriptCore/kjs/testkjs.cpp | 13 +++-- JavaScriptCore/kjs/ustring.cpp | 11 +--- JavaScriptCore/kjs/ustring.h | 6 --- 16 files changed, 250 insertions(+), 210 deletions(-) diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index fdc505494f23..6337ee796a0b 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,78 @@ +2007-11-15 Geoffrey Garen + + Reviewed by Eric Seidel. + + Another round of grammar / parsing cleanup. + + 1. Created distinct parser calls for parsing function bodies vs + programs. This will help later with optimizing global variable access. + + 2. Turned Parser into a singleton. Cleaned up Lexer's singleton + interface. + + 3. Modified Lexer to free a little more memory when done lexing. (Added + FIXMEs for similar issues that I didn't fix.) + + 4. Changed Lexer::makeIdentifier and Lexer::makeUString to start + respecting the arguments passed to them. (No behavior change, but this + problem could have caused serious problems for an unsuspecting user of + these functions.) + + 5. Removed KJS_DEBUG_MEM because it was bit-rotted. + + 6. Removed Parser::prettyPrint because the same work was simpler to do + at the call site. + + 7. Some renames: + + "Parser::accept" => "Parser::didFinishParsing" + "Parser::sid" => "Parser::m_sourceID" + "Lexer::doneParsing" => "Lexer::clear" + "sid" => "sourceId" + "lineno" => "lineNo" + + * JavaScriptCore.exp: + * kjs/Parser.cpp: + (KJS::Parser::Parser): + (KJS::Parser::parseProgram): + (KJS::Parser::parseFunctionBody): + (KJS::Parser::parse): + (KJS::Parser::didFinishParsing): + (KJS::parser): + * kjs/Parser.h: + (KJS::Parser::sourceId): + * kjs/function.cpp: + (KJS::GlobalFuncImp::callAsFunction): + * kjs/function_object.cpp: + (FunctionObjectImp::construct): + * kjs/grammar.y: + * kjs/interpreter.cpp: + (KJS::Interpreter::checkSyntax): + (KJS::Interpreter::evaluate): + * kjs/interpreter.h: + * kjs/lexer.cpp: + (kjsyylex): + (KJS::lexer): + (KJS::Lexer::Lexer): + (KJS::Lexer::~Lexer): + (KJS::Lexer::scanRegExp): + (KJS::Lexer::doneParsing): + (KJS::Lexer::makeIdentifier): + (KJS::Lexer::makeUString): + * kjs/lexer.h: + (KJS::Lexer::pattern): + (KJS::Lexer::flags): + (KJS::Lexer::sawError): + * kjs/nodes.cpp: + (KJS::Node::Node): + (KJS::FunctionBodyNode::FunctionBodyNode): + * kjs/nodes.h: + * kjs/testkjs.cpp: + (prettyPrintScript): + (kjsmain): + * kjs/ustring.cpp: + * kjs/ustring.h: + 2007-11-15 Oliver Hunt Reviewed by Darin. diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp index a3cecd56dc86..fe5aa7951af4 100644 --- a/JavaScriptCore/JavaScriptCore.exp +++ b/JavaScriptCore/JavaScriptCore.exp @@ -163,6 +163,7 @@ __ZN3KJS19InternalFunctionImp4infoE __ZN3KJS19InternalFunctionImpC2EPNS_17FunctionPrototypeERKNS_10IdentifierE __ZN3KJS4List15expandAndAppendEPNS_7JSValueE __ZN3KJS4List7markSetEv +__ZN3KJS4Node5derefEv __ZN3KJS6JSCell9getObjectEv __ZN3KJS6JSCellnwEm __ZN3KJS6JSLock12DropAllLocksC1Ev @@ -172,7 +173,8 @@ __ZN3KJS6JSLock4lockEv __ZN3KJS6JSLock6unlockEv __ZN3KJS6JSLock9lockCountEv __ZN3KJS6Lookup9findEntryEPKNS_9HashTableERKNS_10IdentifierE -__ZN3KJS6Parser11prettyPrintERKNS_7UStringEPiPS1_ +__ZN3KJS6Parser12parseProgramERKNS_7UStringEiPKNS_5UCharEjPiS7_PS1_ +__ZN3KJS6parserEv __ZN3KJS7CStringD1Ev __ZN3KJS7UString3Rep4nullE __ZN3KJS7UString3Rep7destroyEv @@ -206,6 +208,7 @@ __ZN3KJS8JSObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE __ZN3KJS8JSObject14deletePropertyEPNS_9ExecStateEj __ZN3KJS8JSObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE __ZN3KJS8JSObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE +__ZN3KJS8JSObject18getPrimitiveNumberEPNS_9ExecStateERdRPNS_7JSValueE __ZN3KJS8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPPNS_7JSValueE __ZN3KJS8JSObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEi __ZN3KJS8JSObject3putEPNS_9ExecStateEjPNS_7JSValueEi @@ -246,6 +249,7 @@ __ZNK3KJS13ArrayInstance7getItemEj __ZNK3KJS19InternalFunctionImp14implementsCallEv __ZNK3KJS19InternalFunctionImp21implementsHasInstanceEv __ZNK3KJS4List8getSliceEiRS0_ +__ZNK3KJS4Node8toStringEv __ZNK3KJS6JSCell17getTruncatedInt32ERi __ZNK3KJS6JSCell17getTruncatedInt32ERi __ZNK3KJS6JSCell18getTruncatedUInt32ERj @@ -270,7 +274,6 @@ __ZNK3KJS8Bindings8Instance10rootObjectEv __ZNK3KJS8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE __ZNK3KJS8JSObject12defaultValueEPNS_9ExecStateENS_6JSTypeE __ZNK3KJS8JSObject14implementsCallEv -__ZN3KJS8JSObject18getPrimitiveNumberEPNS_9ExecStateERdRPNS_7JSValueE __ZNK3KJS8JSObject19implementsConstructEv __ZNK3KJS8JSObject21implementsHasInstanceEv __ZNK3KJS8JSObject3getEPNS_9ExecStateERKNS_10IdentifierE diff --git a/JavaScriptCore/kjs/Parser.cpp b/JavaScriptCore/kjs/Parser.cpp index 2f64f8323acf..8eef050099b3 100644 --- a/JavaScriptCore/kjs/Parser.cpp +++ b/JavaScriptCore/kjs/Parser.cpp @@ -3,7 +3,7 @@ * This file is part of the KDE libraries * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 2006, 2007 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -30,67 +30,73 @@ #include #include -extern int kjsyyparse(); - namespace KJS { -int Parser::sid = 0; +Parser::Parser() + : m_sourceId(0) +{ +} -static RefPtr* progNode; +PassRefPtr Parser::parseProgram(const UString& sourceURL, int startingLineNumber, + const UChar* code, unsigned length, + int* sourceId, int* errLine, UString* errMsg) +{ + parse(sourceURL, startingLineNumber, code, length, sourceId, errLine, errMsg); + return m_progNode.release(); +} -PassRefPtr Parser::parse(const UString& sourceURL, int startingLineNumber, +PassRefPtr Parser::parseFunctionBody(const UString& sourceURL, int startingLineNumber, const UChar* code, unsigned length, int* sourceId, int* errLine, UString* errMsg) { + parse(sourceURL, startingLineNumber, code, length, sourceId, errLine, errMsg); + return m_progNode.release(); +} + +void Parser::parse(const UString& sourceURL, int startingLineNumber, + const UChar* code, unsigned length, + int* sourceId, int* errLine, UString* errMsg) +{ + ASSERT(!m_progNode); + if (errLine) *errLine = -1; if (errMsg) *errMsg = 0; - if (!progNode) - progNode = new RefPtr; + + Lexer& lexer = KJS::lexer(); - Lexer::curr()->setCode(sourceURL, startingLineNumber, code, length); - *progNode = 0; - sid++; + lexer.setCode(sourceURL, startingLineNumber, code, length); + m_sourceId++; if (sourceId) - *sourceId = sid; - - // Enable this and the #define YYDEBUG in grammar.y to debug a parse error - //extern int kjsyydebug; - //kjsyydebug=1; + *sourceId = m_sourceId; int parseError = kjsyyparse(); - bool lexError = Lexer::curr()->sawError(); - Lexer::curr()->doneParsing(); - PassRefPtr prog = progNode->release(); - *progNode = 0; + bool lexError = lexer.sawError(); + lexer.clear(); Node::clearNewNodes(); if (parseError || lexError) { - int eline = Lexer::curr()->lineNo(); if (errLine) - *errLine = eline; + *errLine = lexer.lineNo(); if (errMsg) *errMsg = "Parse error"; - return 0; + m_progNode = 0; } - - return prog; } -void Parser::accept(PassRefPtr prog) +void Parser::didFinishParsing(PassRefPtr progNode) { - *progNode = prog; + m_progNode = progNode; } -UString Parser::prettyPrint(const UString& code, int* errLine, UString* errMsg) +Parser& parser() { - RefPtr progNode = parse(UString(), 0, code.data(), code.size(), 0, errLine, errMsg); - if (!progNode) - return 0; - - return progNode->toString(); -} + ASSERT(JSLock::currentThreadIsHoldingLock()); + static Parser staticParser; + return staticParser; } + +} // namespace KJS diff --git a/JavaScriptCore/kjs/Parser.h b/JavaScriptCore/kjs/Parser.h index 06c8936496ba..5ba916bce6cf 100644 --- a/JavaScriptCore/kjs/Parser.h +++ b/JavaScriptCore/kjs/Parser.h @@ -3,7 +3,7 @@ * This file is part of the KDE libraries * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 2006, 2007 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,37 +26,44 @@ #define Parser_h #include +#include namespace KJS { - class Node; + class FunctionBodyNode; class ProgramNode; class UString; struct UChar; - /** - * @internal - * - * Parses ECMAScript source code and converts into ProgramNode objects, which - * represent the root of a parse tree. This class provides a convenient workaround - * for the problem of the bison parser working in a static context. - */ - class Parser { + class Parser : Noncopyable { public: - static PassRefPtr parse(const UString& sourceURL, int startingLineNumber, + PassRefPtr parseProgram(const UString& sourceURL, int startingLineNumber, const UChar* code, unsigned length, int* sourceId = 0, int* errLine = 0, UString* errMsg = 0); - static UString prettyPrint(const UString&, int* errLine = 0, UString* errMsg = 0); + PassRefPtr parseFunctionBody(const UString& sourceURL, int startingLineNumber, + const UChar* code, unsigned length, + int* sourceId = 0, int* errLine = 0, UString* errMsg = 0); + + int sourceId() { return m_sourceId; } - static void accept(PassRefPtr); + void didFinishParsing(PassRefPtr); - static void saveNewNode(Node*); + private: + friend Parser& parser(); + + Parser(); // Use parser() instead. + void parse(const UString& sourceURL, int startingLineNumber, + const UChar* code, unsigned length, + int* sourceId = 0, int* errLine = 0, UString* errMsg = 0); - static int sid; + int m_sourceId; + RefPtr m_progNode; }; + + Parser& parser(); // Returns the singleton JavaScript parser. -} // namespace +} // namespace KJS -#endif +#endif // Parser_h diff --git a/JavaScriptCore/kjs/function.cpp b/JavaScriptCore/kjs/function.cpp index fadd37af2153..f445cd3301c3 100644 --- a/JavaScriptCore/kjs/function.cpp +++ b/JavaScriptCore/kjs/function.cpp @@ -77,13 +77,13 @@ JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const L newExec.setException(exec->exception()); Debugger* dbg = exec->dynamicInterpreter()->debugger(); - int sid = -1; - int lineno = -1; + int sourceId = -1; + int lineNo = -1; if (dbg) { - sid = body->sourceId(); - lineno = body->firstLine(); + sourceId = body->sourceId(); + lineNo = body->firstLine(); - bool cont = dbg->callEvent(&newExec,sid,lineno,this,args); + bool cont = dbg->callEvent(&newExec, sourceId, lineNo, this, args); if (!cont) { dbg->imp()->abort(); return jsUndefined(); @@ -102,12 +102,12 @@ JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const L dbg = exec->dynamicInterpreter()->debugger(); if (dbg) { - lineno = body->lastLine(); + lineNo = body->lastLine(); if (comp.complType() == Throw) newExec.setException(comp.value()); - int cont = dbg->returnEvent(&newExec,sid,lineno,this); + int cont = dbg->returnEvent(&newExec, sourceId, lineNo, this); if (!cont) { dbg->imp()->abort(); return jsUndefined(); @@ -761,21 +761,21 @@ JSValue* GlobalFuncImp::callAsFunction(ExecState* exec, JSObject* thisObj, const else { UString s = x->toString(exec); - int sid; + int sourceId; int errLine; UString errMsg; - RefPtr progNode(Parser::parse(UString(), 0, s.data(),s.size(),&sid,&errLine,&errMsg)); + RefPtr progNode(parser().parseProgram(UString(), 0, s.data(), s.size(), &sourceId, &errLine, &errMsg)); Debugger* dbg = exec->dynamicInterpreter()->debugger(); if (dbg) { - bool cont = dbg->sourceParsed(exec, sid, UString(), s, 0, errLine, errMsg); + bool cont = dbg->sourceParsed(exec, sourceId, UString(), s, 0, errLine, errMsg); if (!cont) return jsUndefined(); } // no program node means a syntax occurred if (!progNode) - return throwError(exec, SyntaxError, errMsg, errLine, sid, NULL); + return throwError(exec, SyntaxError, errMsg, errLine, sourceId, NULL); bool switchGlobal = thisObj && thisObj != exec->dynamicInterpreter()->globalObject(); diff --git a/JavaScriptCore/kjs/function_object.cpp b/JavaScriptCore/kjs/function_object.cpp index 922db9b91716..33d3f70d52f0 100644 --- a/JavaScriptCore/kjs/function_object.cpp +++ b/JavaScriptCore/kjs/function_object.cpp @@ -185,16 +185,16 @@ JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args, const } // parse the source code - int sid; + int sourceId; int errLine; UString errMsg; - RefPtr progNode = Parser::parse(sourceURL, lineNumber, body.data(),body.size(),&sid,&errLine,&errMsg); + RefPtr functionBody = parser().parseFunctionBody(sourceURL, lineNumber, body.data(), body.size(), &sourceId, &errLine, &errMsg); // notify debugger that source has been parsed Debugger *dbg = exec->dynamicInterpreter()->debugger(); if (dbg) { // send empty sourceURL to indicate constructed code - bool cont = dbg->sourceParsed(exec, sid, UString(), body, lineNumber, errLine, errMsg); + bool cont = dbg->sourceParsed(exec, sourceId, UString(), body, lineNumber, errLine, errMsg); if (!cont) { dbg->imp()->abort(); return new JSObject(); @@ -202,16 +202,15 @@ JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args, const } // no program node == syntax error - throw a syntax error - if (!progNode) + if (!functionBody) // we can't return a Completion(Throw) here, so just set the exception // and return it - return throwError(exec, SyntaxError, errMsg, errLine, sid, sourceURL); + return throwError(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL); ScopeChain scopeChain; scopeChain.push(exec->lexicalInterpreter()->globalObject()); - FunctionBodyNode *bodyNode = progNode.get(); - FunctionImp* fimp = new FunctionImp(exec, functionName, bodyNode, scopeChain); + FunctionImp* fimp = new FunctionImp(exec, functionName, functionBody.get(), scopeChain); // parse parameter list. throw syntax error on illegal identifiers int len = p.size(); @@ -231,11 +230,11 @@ JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args, const while (i < len && *c == ' ') c++, i++; if (i == len) { - bodyNode->addParam(Identifier(param)); + functionBody->addParam(Identifier(param)); params++; break; } else if (*c == ',') { - bodyNode->addParam(Identifier(param)); + functionBody->addParam(Identifier(param)); params++; c++, i++; continue; diff --git a/JavaScriptCore/kjs/grammar.y b/JavaScriptCore/kjs/grammar.y index 0a2bb821cf73..d8589e82fe4c 100644 --- a/JavaScriptCore/kjs/grammar.y +++ b/JavaScriptCore/kjs/grammar.y @@ -42,7 +42,8 @@ #define YYENABLE_NLS 0 /* default values for bison */ -#define YYDEBUG 0 +#define YYDEBUG 0 // Set to 1 to debug a parse error. +#define kjsyydebug 0 // Set to 1 to debug a parse error. #if !PLATFORM(DARWIN) // avoid triggering warnings in older bison #define YYERROR_VERBOSE @@ -220,14 +221,16 @@ Literal: | NUMBER { $$ = makeNumberNode($1); } | STRING { $$ = new StringNode($1); } | '/' /* regexp */ { - Lexer *l = Lexer::curr(); - if (!l->scanRegExp()) YYABORT; - $$ = new RegExpNode(l->pattern, l->flags); + Lexer& l = lexer(); + if (!l.scanRegExp()) + YYABORT; + $$ = new RegExpNode(l.pattern(), l.flags()); } | DIVEQUAL /* regexp with /= */ { - Lexer *l = Lexer::curr(); - if (!l->scanRegExp()) YYABORT; - $$ = new RegExpNode("=" + l->pattern, l->flags); + Lexer& l = lexer(); + if (!l.scanRegExp()) + YYABORT; + $$ = new RegExpNode("=" + l.pattern(), l.flags()); } ; @@ -876,8 +879,8 @@ FunctionBody: ; Program: - /* not in spec */ { Parser::accept(new ProgramNode(new SourceElements)); } - | SourceElements { Parser::accept(new ProgramNode($1->release())); } + /* not in spec */ { parser().didFinishParsing(new ProgramNode(new SourceElements)); } + | SourceElements { parser().didFinishParsing(new ProgramNode($1->release())); } ; SourceElements: @@ -1090,5 +1093,5 @@ int yyerror(const char *) /* may we automatically insert a semicolon ? */ static bool allowAutomaticSemicolon() { - return yychar == '}' || yychar == 0 || Lexer::curr()->prevTerminator(); + return yychar == '}' || yychar == 0 || lexer().prevTerminator(); } diff --git a/JavaScriptCore/kjs/interpreter.cpp b/JavaScriptCore/kjs/interpreter.cpp index ef3664805137..a338a4daa9f8 100644 --- a/JavaScriptCore/kjs/interpreter.cpp +++ b/JavaScriptCore/kjs/interpreter.cpp @@ -308,7 +308,7 @@ Completion Interpreter::checkSyntax(const UString& sourceURL, int startingLineNu int errLine; UString errMsg; - RefPtr progNode = Parser::parse(sourceURL, startingLineNumber, code, codeLength, 0, &errLine, &errMsg); + RefPtr progNode = parser().parseProgram(sourceURL, startingLineNumber, code, codeLength, 0, &errLine, &errMsg); if (!progNode) return Completion(Throw, Error::create(&m_globalExec, SyntaxError, errMsg, errLine, 0, sourceURL)); return Completion(Normal); @@ -328,21 +328,21 @@ Completion Interpreter::evaluate(const UString& sourceURL, int startingLineNumbe return Completion(Throw, Error::create(&m_globalExec, GeneralError, "Recursion too deep")); // parse the source code - int sid; + int sourceId; int errLine; UString errMsg; - RefPtr progNode = Parser::parse(sourceURL, startingLineNumber, code, codeLength, &sid, &errLine, &errMsg); + RefPtr progNode = parser().parseProgram(sourceURL, startingLineNumber, code, codeLength, &sourceId, &errLine, &errMsg); // notify debugger that source has been parsed if (m_debugger) { - bool cont = m_debugger->sourceParsed(&m_globalExec, sid, sourceURL, UString(code, codeLength), startingLineNumber, errLine, errMsg); + bool cont = m_debugger->sourceParsed(&m_globalExec, sourceId, sourceURL, UString(code, codeLength), startingLineNumber, errLine, errMsg); if (!cont) return Completion(Break); } // no program node means a syntax error occurred if (!progNode) - return Completion(Throw, Error::create(&m_globalExec, SyntaxError, errMsg, errLine, sid, sourceURL)); + return Completion(Throw, Error::create(&m_globalExec, SyntaxError, errMsg, errLine, sourceId, sourceURL)); m_globalExec.clearException(); @@ -604,20 +604,6 @@ void Interpreter::mark() m_UriErrorPrototype->mark(); } -#ifdef KJS_DEBUG_MEM -#include "lexer.h" -void Interpreter::finalCheck() -{ - fprintf(stderr,"Interpreter::finalCheck()\n"); - Collector::collect(); - - Node::finalCheck(); - Collector::finalCheck(); - Lexer::globalClear(); - UString::globalClear(); -} -#endif - static bool printExceptions = false; bool Interpreter::shouldPrintExceptions() diff --git a/JavaScriptCore/kjs/interpreter.h b/JavaScriptCore/kjs/interpreter.h index d03dbcf95860..24fefe3c1001 100644 --- a/JavaScriptCore/kjs/interpreter.h +++ b/JavaScriptCore/kjs/interpreter.h @@ -291,13 +291,6 @@ namespace KJS { */ virtual void mark(); -#ifdef KJS_DEBUG_MEM - /** - * @internal - */ - static void finalCheck(); -#endif - static bool shouldPrintExceptions(); static void setShouldPrintExceptions(bool); diff --git a/JavaScriptCore/kjs/lexer.cpp b/JavaScriptCore/kjs/lexer.cpp index 09c12607d609..0bdccd6177f8 100644 --- a/JavaScriptCore/kjs/lexer.cpp +++ b/JavaScriptCore/kjs/lexer.cpp @@ -51,15 +51,24 @@ extern YYLTYPE kjsyylloc; // global bison variable holding token info // a bridge for yacc from the C world to C++ int kjsyylex() { - return Lexer::curr()->lex(); + return lexer().lex(); } namespace KJS { -static Lexer* currLexer = 0; - static bool isDecimalDigit(int); +Lexer& lexer() +{ + ASSERT(JSLock::currentThreadIsHoldingLock()); + + // FIXME: We'd like to avoid calling new here, but we don't currently + // support tearing down the Lexer at app quit time, since that would involve + // tearing down its UString data members without holding the JSLock. + static Lexer* staticLexer = new Lexer; + return *staticLexer; +} + Lexer::Lexer() : yylineno(1), size8(128), size16(128), restrKeyword(false), @@ -75,33 +84,14 @@ Lexer::Lexer() // allocate space for read buffers buffer8 = new char[size8]; buffer16 = new KJS::UChar[size16]; - currLexer = this; } Lexer::~Lexer() { - doneParsing(); delete [] buffer8; delete [] buffer16; } -Lexer *Lexer::curr() -{ - if (!currLexer) { - // create singleton instance - currLexer = new Lexer(); - } - return currLexer; -} - -#ifdef KJS_DEBUG_MEM -void Lexer::globalClear() -{ - delete currLexer; - currLexer = 0L; -} -#endif - void Lexer::setCode(const UString &sourceURL, int startingLineNumber, const KJS::UChar *c, unsigned int len) { yylineno = 1 + startingLineNumber; @@ -785,6 +775,7 @@ unsigned char Lexer::convertHex(int c1, int c2) KJS::UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4) { + // FIXME: This conversion is lossy. See http://bugs.webkit.org/show_bug.cgi?id=4920. return KJS::UChar((convertHex(c1) << 4) + convertHex(c2), (convertHex(c3) << 4) + convertHex(c4)); } @@ -850,7 +841,7 @@ bool Lexer::scanRegExp() !lastWasEscape && (current == '\\'); } else { // end of regexp - pattern = UString(buffer16, pos16); + m_pattern = UString(buffer16, pos16); pos16 = 0; shift(1); break; @@ -862,58 +853,57 @@ bool Lexer::scanRegExp() record16(current); shift(1); } - flags = UString(buffer16, pos16); + m_flags = UString(buffer16, pos16); return true; } - -void Lexer::doneParsing() +void Lexer::clear() { - for (unsigned i = 0; i < numIdentifiers; i++) { + for (unsigned i = 0; i < numIdentifiers; i++) delete identifiers[i]; - } fastFree(identifiers); identifiers = 0; numIdentifiers = 0; identifiersCapacity = 0; - for (unsigned i = 0; i < numStrings; i++) { + for (unsigned i = 0; i < numStrings; i++) delete strings[i]; - } fastFree(strings); strings = 0; numStrings = 0; stringsCapacity = 0; + + m_pattern = 0; + m_flags = 0; + m_sourceURL = 0; } const int initialCapacity = 64; const int growthFactor = 2; -// FIXME: this completely ignores its parameters, instead using buffer16 and pos16 - wtf? -Identifier *Lexer::makeIdentifier(KJS::UChar*, unsigned int) +Identifier* Lexer::makeIdentifier(KJS::UChar* buffer, unsigned int pos) { if (numIdentifiers == identifiersCapacity) { identifiersCapacity = (identifiersCapacity == 0) ? initialCapacity : identifiersCapacity *growthFactor; identifiers = (KJS::Identifier **)fastRealloc(identifiers, sizeof(KJS::Identifier *) * identifiersCapacity); } - KJS::Identifier *identifier = new KJS::Identifier(buffer16, pos16); + KJS::Identifier *identifier = new KJS::Identifier(buffer, pos); identifiers[numIdentifiers++] = identifier; return identifier; } -// FIXME: this completely ignores its parameters, instead using buffer16 and pos16 - wtf? -UString *Lexer::makeUString(KJS::UChar*, unsigned int) +UString* Lexer::makeUString(KJS::UChar* buffer, unsigned int pos) { if (numStrings == stringsCapacity) { stringsCapacity = (stringsCapacity == 0) ? initialCapacity : stringsCapacity *growthFactor; strings = (UString **)fastRealloc(strings, sizeof(UString *) * stringsCapacity); } - UString *string = new UString(buffer16, pos16); + UString *string = new UString(buffer, pos); strings[numStrings++] = string; return string; } -} +} // namespace KJS diff --git a/JavaScriptCore/kjs/lexer.h b/JavaScriptCore/kjs/lexer.h index 9bddf8e48698..c7acd27ec0d9 100644 --- a/JavaScriptCore/kjs/lexer.h +++ b/JavaScriptCore/kjs/lexer.h @@ -2,6 +2,7 @@ /* * This file is part of the KDE libraries * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2007 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -20,24 +21,18 @@ * */ -#ifndef _KJSLEXER_H_ -#define _KJSLEXER_H_ +#ifndef Lexer_h +#define Lexer_h #include "ustring.h" - namespace KJS { class Identifier; - class RegExp; - class Lexer { + class Lexer : Noncopyable { public: - Lexer(); - ~Lexer(); - static Lexer *curr(); - void setCode(const UString &sourceURL, int startingLineNumber, const UChar *c, unsigned int len); int lex(); @@ -75,14 +70,30 @@ namespace KJS { Bad }; bool scanRegExp(); - UString pattern, flags; + const UString& pattern() const { return m_pattern; } + const UString& flags() const { return m_flags; } + + static unsigned char convertHex(int); + static unsigned char convertHex(int c1, int c2); + static UChar convertUnicode(int c1, int c2, int c3, int c4); + static bool isIdentStart(int); + static bool isIdentPart(int); + static bool isHexDigit(int); + + bool sawError() const { return error; } + + void clear(); private: + friend Lexer& lexer(); + Lexer(); + ~Lexer(); + int yylineno; UString m_sourceURL; bool done; - char *buffer8; - UChar *buffer16; + char *buffer8; // FIXME: This buffer is never deallocated. + UChar *buffer16; // FIXME: This buffer is never deallocated. unsigned int size8, size16; unsigned int pos8, pos16; bool terminator; @@ -109,25 +120,6 @@ namespace KJS { int matchPunctuator(int c1, int c2, int c3, int c4); static unsigned short singleEscape(unsigned short); static unsigned short convertOctal(int c1, int c2, int c3); - public: - static unsigned char convertHex(int); - static unsigned char convertHex(int c1, int c2); - static UChar convertUnicode(int c1, int c2, int c3, int c4); - static bool isIdentStart(int); - static bool isIdentPart(int); - static bool isHexDigit(int); - -#ifdef KJS_DEBUG_MEM - /** - * Clear statically allocated resources - */ - static void globalClear(); -#endif - - bool sawError() const { return error; } - void doneParsing(); - - private: void record8(int); void record16(int); @@ -154,12 +146,13 @@ namespace KJS { KJS::Identifier **identifiers; unsigned int numIdentifiers; unsigned int identifiersCapacity; - - // for future extensions - class LexerPrivate; - LexerPrivate *priv; + + UString m_pattern; + UString m_flags; }; + + Lexer& lexer(); // Returns the singletone JavaScript lexer. -} // namespace +} // namespace KJS -#endif +#endif // Lexer_h diff --git a/JavaScriptCore/kjs/nodes.cpp b/JavaScriptCore/kjs/nodes.cpp index 4b97e553798e..1e0ac9732df4 100644 --- a/JavaScriptCore/kjs/nodes.cpp +++ b/JavaScriptCore/kjs/nodes.cpp @@ -132,7 +132,7 @@ Node::Node() #ifndef NDEBUG ++NodeCounter::count; #endif - m_line = Lexer::curr()->lineNo(); + m_line = lexer().lineNo(); if (!newNodes) newNodes = new HashSet; newNodes->add(this); @@ -145,7 +145,7 @@ Node::Node(JSType expectedReturn) #ifndef NDEBUG ++NodeCounter::count; #endif - m_line = Lexer::curr()->lineNo(); + m_line = lexer().lineNo(); if (!newNodes) newNodes = new HashSet; newNodes->add(this); @@ -4412,8 +4412,8 @@ Completion TryNode::execute(ExecState *exec) FunctionBodyNode::FunctionBodyNode(SourceElements* children) : BlockNode(children) - , m_sourceURL(Lexer::curr()->sourceURL()) - , m_sourceId(Parser::sid) + , m_sourceURL(lexer().sourceURL()) + , m_sourceId(parser().sourceId()) , m_initializedDeclarationStacks(false) , m_initializedSymbolTable(false) , m_optimizedResolveNodes(false) diff --git a/JavaScriptCore/kjs/nodes.h b/JavaScriptCore/kjs/nodes.h index ce2d902c40bc..aa10317ae001 100644 --- a/JavaScriptCore/kjs/nodes.h +++ b/JavaScriptCore/kjs/nodes.h @@ -49,6 +49,7 @@ namespace KJS { class FuncDeclNode; + class Node; class PropertyListNode; class SourceStream; class VarDeclNode; diff --git a/JavaScriptCore/kjs/testkjs.cpp b/JavaScriptCore/kjs/testkjs.cpp index 7bf864f1ed02..9d4178d9b646 100644 --- a/JavaScriptCore/kjs/testkjs.cpp +++ b/JavaScriptCore/kjs/testkjs.cpp @@ -23,10 +23,11 @@ #include "config.h" +#include "JSGlobalObject.h" #include "JSLock.h" #include "Parser.h" #include "collector.h" -#include "JSGlobalObject.h" +#include "nodes.h" #include "object.h" #include "protect.h" #include @@ -245,13 +246,14 @@ static bool prettyPrintScript(const UString& fileName, const Vector& scrip { int errLine = 0; UString errMsg; - UString s = Parser::prettyPrint(script.data(), &errLine, &errMsg); - if (s.isNull()) { + UString scriptUString(script.data()); + RefPtr programNode = parser().parseProgram(fileName, 0, scriptUString.data(), scriptUString.size(), 0, &errLine, &errMsg); + if (!programNode) { fprintf(stderr, "%s:%d: %s.\n", fileName.UTF8String().c_str(), errLine, errMsg.UTF8String().c_str()); return false; } - printf("%s\n", s.UTF8String().c_str()); + printf("%s\n", programNode->toString().UTF8String().c_str()); return true; } @@ -313,9 +315,6 @@ int kjsmain(int argc, char** argv) Collector::collect(); #endif -#ifdef KJS_DEBUG_MEM - Interpreter::finalCheck(); -#endif return success ? 0 : 3; } diff --git a/JavaScriptCore/kjs/ustring.cpp b/JavaScriptCore/kjs/ustring.cpp index 5544aeae2e09..b99a29e22391 100644 --- a/JavaScriptCore/kjs/ustring.cpp +++ b/JavaScriptCore/kjs/ustring.cpp @@ -176,7 +176,7 @@ static unsigned short almostUChar; UString::Rep UString::Rep::null = { 0, 0, 1, 0, 0, &UString::Rep::null, 0, 0, 0, 0, 0 }; UString::Rep UString::Rep::empty = { 0, 0, 1, 0, 0, &UString::Rep::empty, reinterpret_cast(&almostUChar), 0, 0, 0, 0 }; const int normalStatBufferSize = 4096; -static char *statBuffer = 0; +static char *statBuffer = 0; // FIXME: This buffer is never deallocated. static int statBufferSize = 0; PassRefPtr UString::Rep::createCopying(const UChar *d, int l) @@ -886,15 +886,6 @@ char *UString::ascii() const return statBuffer; } -#ifdef KJS_DEBUG_MEM -void UString::globalClear() -{ - delete [] statBuffer; - statBuffer = 0; - statBufferSize = 0; -} -#endif - UString &UString::operator=(const char *c) { if (!c) { diff --git a/JavaScriptCore/kjs/ustring.h b/JavaScriptCore/kjs/ustring.h index 412514ba12f8..86267ce79468 100644 --- a/JavaScriptCore/kjs/ustring.h +++ b/JavaScriptCore/kjs/ustring.h @@ -382,12 +382,6 @@ namespace KJS { * Static instance of a null string. */ static const UString &null(); -#ifdef KJS_DEBUG_MEM - /** - * Clear statically allocated resources. - */ - static void globalClear(); -#endif Rep* rep() const { return m_rep.get(); } UString(PassRefPtr r) : m_rep(r) { ASSERT(m_rep); } -- 2.36.0