diff options
Diffstat (limited to 'JavaScriptCore')
72 files changed, 4676 insertions, 256 deletions
diff --git a/JavaScriptCore/API/JSClassRef.h b/JavaScriptCore/API/JSClassRef.h index ae60aad..5a3a17e 100644 --- a/JavaScriptCore/API/JSClassRef.h +++ b/JavaScriptCore/API/JSClassRef.h @@ -33,7 +33,6 @@ #include <runtime/UString.h> #include <runtime/WeakGCPtr.h> #include <wtf/HashMap.h> -#include <wtf/RefCounted.h> struct StaticValueEntry : FastAllocBase { StaticValueEntry(JSObjectGetPropertyCallback _getProperty, JSObjectSetPropertyCallback _setProperty, JSPropertyAttributes _attributes) diff --git a/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp b/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp index 9beeb82..8182075 100644 --- a/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp +++ b/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp @@ -32,7 +32,6 @@ #include "JSValue.h" #include "JSWeakObjectMapRefInternal.h" #include <wtf/HashMap.h> -#include <wtf/RefCounted.h> #include <wtf/text/StringHash.h> using namespace WTF; diff --git a/JavaScriptCore/CMakeLists.txt b/JavaScriptCore/CMakeLists.txt index d4a85d0..c1946ff 100644 --- a/JavaScriptCore/CMakeLists.txt +++ b/JavaScriptCore/CMakeLists.txt @@ -54,16 +54,19 @@ SET(JavaScriptCore_SOURCES jit/ExecutableAllocatorPosix.cpp jit/ExecutableAllocatorSymbian.cpp jit/ExecutableAllocatorWin.cpp - jit/JITStubs.cpp - jit/JITOpcodes.cpp - jit/JITOpcodes32_64.cpp - jit/JITPropertyAccess.cpp - jit/JITPropertyAccess32_64.cpp + jit/JITArithmetic32_64.cpp jit/JITArithmetic.cpp - jit/JITCall.cpp jit/JITCall32_64.cpp + jit/JITCall.cpp jit/JIT.cpp + jit/JITOpcodes32_64.cpp + jit/JITOpcodes.cpp + jit/JITPropertyAccess32_64.cpp + jit/JITPropertyAccess.cpp + jit/JITStubs.cpp + jit/ThunkGenerators.cpp + parser/JSParser.cpp parser/Lexer.cpp parser/Nodes.cpp parser/Parser.cpp @@ -149,6 +152,7 @@ SET(JavaScriptCore_SOURCES runtime/PropertySlot.cpp runtime/PrototypeFunction.cpp runtime/RegExp.cpp + runtime/RegExpCache.cpp runtime/RegExpConstructor.cpp runtime/RegExpObject.cpp runtime/RegExpPrototype.cpp diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index 8d5b59e..ff017ca 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,957 @@ +2010-06-25 Jedrzej Nowacki <jedrzej.nowacki@nokia.com> + + Reviewed by Simon Hausmann. + + New QtScript API; setPrototype() and prototype(). + + This patch implements QScriptValue's prototype accessors. + + [Qt] QScriptValue should have accessors to a prototype. + https://bugs.webkit.org/show_bug.cgi?id=39356 + + * qt/api/qscriptvalue.cpp: + (QScriptValue::prototype): + (QScriptValue::setPrototype): + * qt/api/qscriptvalue.h: + * qt/api/qscriptvalue_p.h: + (QScriptValuePrivate::prototype): + (QScriptValuePrivate::setPrototype): + * qt/tests/qscriptvalue/tst_qscriptvalue.cpp: + (tst_QScriptValue::getSetPrototype): + * qt/tests/qscriptvalue/tst_qscriptvalue.h: + +2010-06-25 Lucas De Marchi <lucas.demarchi@profusion.mobi> + + Reviewed by Kenneth Rohde Christiansen. + + [CMake] Add option to enable JIT. + JIT is disabled by default, but now it's possible to enable it through + an option to CMake: -DENABLE_JIT will enable it. + https://bugs.webkit.org/show_bug.cgi?id=40936 + + * CMakeLists.txt: Add missing files and re-sort. + +2010-06-25 Lucas De Marchi <lucas.demarchi@profusion.mobi> + + Reviewed by Gustavo Noronha Silva. + + [CMake] Remove unused variable in EFL build system. It was previously + being used to set the flags of each port but it was superseded by + other flags. + https://bugs.webkit.org/show_bug.cgi?id=40931 + + * jsc/CMakeLists.txt: + +2010-06-25 Nathan Lawrence <nlawrence@apple.com> + + Reviewed by Geoffrey Garen. + + Aligning AssemblerBuffer to 128 bytes gives a 0.4% speedup on + sunspider. + + * assembler/AssemblerBuffer.h: + (JSC::AssemblerBuffer::AssemblerBuffer): + +2010-06-25 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r61842. + http://trac.webkit.org/changeset/61842 + https://bugs.webkit.org/show_bug.cgi?id=41208 + + It broke Windows build (Requested by Ossy_ on #webkit). + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * wtf/OwnPtrCommon.h: + * wtf/brew/OwnPtrBrew.h: Removed. + * wtf/win/OwnPtrWin.h: Removed. + +2010-06-25 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r61833. + http://trac.webkit.org/changeset/61833 + https://bugs.webkit.org/show_bug.cgi?id=41205 + + It broke Leopard and GTK (Requested by Ossy_ on #webkit). + + * runtime/RegExp.cpp: + (JSC::RegExp::RegExp): + (JSC::RegExp::create): + * runtime/RegExp.h: + * runtime/RegExpCache.cpp: + (JSC::RegExpCache::lookupOrCreate): + (JSC::RegExpCache::create): + * runtime/RegExpCache.h: + +2010-06-25 Kwang Yul Seo <skyul@company100.net> + + Reviewed by Adam Barth. + + Change OwnPtrCommon to include platform-specific headers + https://bugs.webkit.org/show_bug.cgi?id=40279 + + Adding new type to OwnPtrCommon needlessly causes all ports to do full rebuilds. + Change OwnPtrCommon to include platform-specific headers to avoid all ports rebuilds. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * wtf/OwnPtrCommon.h: + * wtf/brew/OwnPtrBrew.h: Added. + * wtf/win/OwnPtrWin.h: Added. + +2010-06-25 Patrick Gansterer <paroga@paroga.com> + + Reviewed by Darin Adler. + + Add the possibility for a head and footer section to create_jit_stubs. + https://bugs.webkit.org/show_bug.cgi?id=36050 + + * create_jit_stubs: + +2010-06-24 Renata Hodovan <reni@inf.u-szeged.hu> + + Reviewed by Geoffrey Garen. + + Merge RegExp constructor and RegExp::create methods into one. + Both of function are called with tree parameters and check whether + flags (the third param) is given or not. + Simplify hash lookups in RegExpCache::create with giving them an extra + iterator parameter. + https://bugs.webkit.org/show_bug.cgi?id=41055 + + * runtime/RegExp.cpp: + (JSC::RegExp::RegExp): + * runtime/RegExp.h: + * runtime/RegExpCache.cpp: + (JSC::RegExpCache::lookupOrCreate): + (JSC::RegExpCache::create): + * runtime/RegExpCache.h: + +2010-06-24 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + Incorrect use of '+ 4' and 0 instead of tag and payload offsets in JSValue32_64 + https://bugs.webkit.org/show_bug.cgi?id=41193 + + I noticed a use of '+ 4' in some of the 32_64 code paths and realised there + were a few places where endianness was being hardcoded. This patch fixes + the errors i could find through code inspection. + + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_resolve_global): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emit_op_put_by_val): + (JSC::JIT::compileGetDirectOffset): + (JSC::JIT::privateCompilePutByIdTransition): + (JSC::JIT::patchGetByIdSelf): + (JSC::JIT::patchPutByIdReplace): + +2010-06-24 Oliver Hunt <oliver@apple.com> + + Build fix + + Temporarily get the tiger bot working again by disabling the + new JS parser. GCC on tiger is miscompiling the parser and + I don't have access to a tiger machine right now. + + * wtf/Platform.h: + + 2010-06-21 Nathan Lawrence <nlawrence@apple.com> + + Reviewed by Geoff Garen. + + https://bugs.webkit.org/show_bug.cgi?id=40128 + Fixed broken debug functionality. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::dumpRegisters): + Fixed to work with updated call frame. + * runtime/JSImmediate.h: + (JSC::JSValue::isCell): + Added assert for aligned cell. + * runtime/JSValue.cpp: + (JSC::JSValue::description): + Fixed to work with current JSValue implementation. + * runtime/JSZombie.cpp: + (JSC::JSZombie::leakedZombieStructure): + JSombies compile again. + +2010-06-24 Leandro Pereira <leandro@profusion.mobi> + + Unreviewed build fix. + + * CMakeLists.txt: Add JSParser.cpp. + +2010-06-24 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + Single character string replacement may replace too many characters + https://bugs.webkit.org/show_bug.cgi?id=41138 + <rdar://problem/8097496> + + Simple fix to stop the rope path of single character replacement + once the first replacement occurs. + + * runtime/JSString.cpp: + (JSC::JSString::replaceCharacter): + +2010-06-24 Gabor Loki <loki@webkit.org> + + Reviewed by Gavin Barraclough. + + Fix the length of instruction stream controlled by constant pool + https://bugs.webkit.org/show_bug.cgi?id=40293 + + The initial/maximum length of instruction stream (m_maxDistance) should + be set when the first constant arrives to the constant pool. Otherwise + the constant pool could be placed into an uninterrupted sequence. + + * assembler/AssemblerBufferWithConstantPool.h: + (JSC::): + +2010-06-24 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + We assume bytecodeOffset will always return a value > 1, + so we adjust the failure case to return 1 instead of 0. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::bytecodeOffset): + +2010-06-23 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Custom-written JavaScript parser + https://bugs.webkit.org/show_bug.cgi?id=34019 + + Implement a recursive descent parser similar to that used by V8 and + SpiderMonkey. Greater than 2x improvement in SunSpider parsing tests. + + The parser consists of a JSParser class that uses a TreeBuilder to actually + build the AST. There are currently two builders -- the ASTBuilder and + SyntaxChecker which separate the job of building an AST for code generation + and simply checking syntactic correctness. + + There's still some less than ideal code remaining in the parser to allow + us to retain the existing lexing code with minimal changes. We'll tidy + this up at a later date. + + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.pro: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * parser/ASTBuilder.h: Added. + (JSC::ASTBuilder::BinaryOpInfo::BinaryOpInfo): + (JSC::ASTBuilder::AssignmentInfo::AssignmentInfo): + (JSC::ASTBuilder::ASTBuilder): + (JSC::ASTBuilder::createSourceElements): + (JSC::ASTBuilder::varDeclarations): + (JSC::ASTBuilder::funcDeclarations): + (JSC::ASTBuilder::features): + (JSC::ASTBuilder::numConstants): + (JSC::ASTBuilder::appendToComma): + (JSC::ASTBuilder::createCommaExpr): + (JSC::ASTBuilder::createLogicalNot): + (JSC::ASTBuilder::createUnaryPlus): + (JSC::ASTBuilder::createVoid): + (JSC::ASTBuilder::thisExpr): + (JSC::ASTBuilder::createResolve): + (JSC::ASTBuilder::createObjectLiteral): + (JSC::ASTBuilder::createArray): + (JSC::ASTBuilder::createNumberExpr): + (JSC::ASTBuilder::createString): + (JSC::ASTBuilder::createBoolean): + (JSC::ASTBuilder::createNull): + (JSC::ASTBuilder::createBracketAccess): + (JSC::ASTBuilder::createDotAccess): + (JSC::ASTBuilder::createRegex): + (JSC::ASTBuilder::createNewExpr): + (JSC::ASTBuilder::createConditionalExpr): + (JSC::ASTBuilder::createAssignResolve): + (JSC::ASTBuilder::createFunctionExpr): + (JSC::ASTBuilder::createFunctionBody): + (JSC::ASTBuilder::createGetterOrSetterProperty): + (JSC::ASTBuilder::createArguments): + (JSC::ASTBuilder::createArgumentsList): + (JSC::ASTBuilder::createProperty): + (JSC::ASTBuilder::createPropertyList): + (JSC::ASTBuilder::createElementList): + (JSC::ASTBuilder::createFormalParameterList): + (JSC::ASTBuilder::createClause): + (JSC::ASTBuilder::createClauseList): + (JSC::ASTBuilder::setUsesArguments): + (JSC::ASTBuilder::createFuncDeclStatement): + (JSC::ASTBuilder::createBlockStatement): + (JSC::ASTBuilder::createExprStatement): + (JSC::ASTBuilder::createIfStatement): + (JSC::ASTBuilder::createForLoop): + (JSC::ASTBuilder::createForInLoop): + (JSC::ASTBuilder::createEmptyStatement): + (JSC::ASTBuilder::createVarStatement): + (JSC::ASTBuilder::createReturnStatement): + (JSC::ASTBuilder::createBreakStatement): + (JSC::ASTBuilder::createContinueStatement): + (JSC::ASTBuilder::createTryStatement): + (JSC::ASTBuilder::createSwitchStatement): + (JSC::ASTBuilder::createWhileStatement): + (JSC::ASTBuilder::createDoWhileStatement): + (JSC::ASTBuilder::createLabelStatement): + (JSC::ASTBuilder::createWithStatement): + (JSC::ASTBuilder::createThrowStatement): + (JSC::ASTBuilder::createDebugger): + (JSC::ASTBuilder::createConstStatement): + (JSC::ASTBuilder::appendConstDecl): + (JSC::ASTBuilder::appendStatement): + (JSC::ASTBuilder::addVar): + (JSC::ASTBuilder::combineCommaNodes): + (JSC::ASTBuilder::evalCount): + (JSC::ASTBuilder::appendBinaryExpressionInfo): + (JSC::ASTBuilder::operatorStackPop): + (JSC::ASTBuilder::operatorStackHasHigherPrecedence): + (JSC::ASTBuilder::getFromOperandStack): + (JSC::ASTBuilder::shrinkOperandStackBy): + (JSC::ASTBuilder::appendBinaryOperation): + (JSC::ASTBuilder::operatorStackAppend): + (JSC::ASTBuilder::popOperandStack): + (JSC::ASTBuilder::appendUnaryToken): + (JSC::ASTBuilder::unaryTokenStackLastType): + (JSC::ASTBuilder::unaryTokenStackLastStart): + (JSC::ASTBuilder::unaryTokenStackRemoveLast): + (JSC::ASTBuilder::assignmentStackAppend): + (JSC::ASTBuilder::createAssignment): + (JSC::ASTBuilder::Scope::Scope): + (JSC::ASTBuilder::setExceptionLocation): + (JSC::ASTBuilder::incConstants): + (JSC::ASTBuilder::usesThis): + (JSC::ASTBuilder::usesCatch): + (JSC::ASTBuilder::usesClosures): + (JSC::ASTBuilder::usesArguments): + (JSC::ASTBuilder::usesAssignment): + (JSC::ASTBuilder::usesWith): + (JSC::ASTBuilder::usesEval): + (JSC::ASTBuilder::createNumber): + (JSC::ASTBuilder::makeTypeOfNode): + (JSC::ASTBuilder::makeDeleteNode): + (JSC::ASTBuilder::makeNegateNode): + (JSC::ASTBuilder::makeBitwiseNotNode): + (JSC::ASTBuilder::makeMultNode): + (JSC::ASTBuilder::makeDivNode): + (JSC::ASTBuilder::makeAddNode): + (JSC::ASTBuilder::makeSubNode): + (JSC::ASTBuilder::makeLeftShiftNode): + (JSC::ASTBuilder::makeRightShiftNode): + (JSC::ASTBuilder::makeFunctionCallNode): + (JSC::ASTBuilder::makeBinaryNode): + (JSC::ASTBuilder::makeAssignNode): + (JSC::ASTBuilder::makePrefixNode): + (JSC::ASTBuilder::makePostfixNode): + * parser/JSParser.cpp: Added. + (JSC::JSParser::AllowInOverride::AllowInOverride): + (JSC::JSParser::AllowInOverride::~AllowInOverride): + (JSC::JSParser::token): + (JSC::JSParser::next): + (JSC::JSParser::consume): + (JSC::JSParser::match): + (JSC::JSParser::tokenStart): + (JSC::JSParser::tokenLine): + (JSC::JSParser::tokenEnd): + (JSC::JSParser::): + (JSC::JSParser::autoSemiColon): + (JSC::JSParser::canRecurse): + (JSC::JSParser::lastTokenEnd): + (JSC::jsParse): + (JSC::JSParser::JSParser): + (JSC::JSParser::parseProgram): + (JSC::JSParser::allowAutomaticSemicolon): + (JSC::JSParser::parseSourceElements): + (JSC::JSParser::parseVarDeclaration): + (JSC::JSParser::parseConstDeclaration): + (JSC::JSParser::parseDoWhileStatement): + (JSC::JSParser::parseWhileStatement): + (JSC::JSParser::parseVarDeclarationList): + (JSC::JSParser::parseConstDeclarationList): + (JSC::JSParser::parseForStatement): + (JSC::JSParser::parseBreakStatement): + (JSC::JSParser::parseContinueStatement): + (JSC::JSParser::parseReturnStatement): + (JSC::JSParser::parseThrowStatement): + (JSC::JSParser::parseWithStatement): + (JSC::JSParser::parseSwitchStatement): + (JSC::JSParser::parseSwitchClauses): + (JSC::JSParser::parseSwitchDefaultClause): + (JSC::JSParser::parseTryStatement): + (JSC::JSParser::parseDebuggerStatement): + (JSC::JSParser::parseBlockStatement): + (JSC::JSParser::parseStatement): + (JSC::JSParser::parseFormalParameters): + (JSC::JSParser::parseFunctionBody): + (JSC::JSParser::parseFunctionInfo): + (JSC::JSParser::parseFunctionDeclaration): + (JSC::JSParser::parseExpressionOrLabelStatement): + (JSC::JSParser::parseExpressionStatement): + (JSC::JSParser::parseIfStatement): + (JSC::JSParser::parseExpression): + (JSC::JSParser::parseAssignmentExpression): + (JSC::JSParser::parseConditionalExpression): + (JSC::isUnaryOp): + (JSC::JSParser::isBinaryOperator): + (JSC::JSParser::parseBinaryExpression): + (JSC::JSParser::parseProperty): + (JSC::JSParser::parseObjectLiteral): + (JSC::JSParser::parseArrayLiteral): + (JSC::JSParser::parsePrimaryExpression): + (JSC::JSParser::parseArguments): + (JSC::JSParser::parseMemberExpression): + (JSC::JSParser::parseUnaryExpression): + * parser/JSParser.h: Added. + (JSC::): + (JSC::JSTokenInfo::JSTokenInfo): + * parser/Lexer.cpp: + (JSC::Lexer::lex): + * parser/Lexer.h: + (JSC::Lexer::setLastLineNumber): + (JSC::Lexer::lastLineNumber): + * parser/NodeConstructors.h: + (JSC::Node::Node): + * parser/Parser.cpp: + (JSC::Parser::parse): + * parser/SyntaxChecker.h: Added. + (JSC::SyntaxChecker::SyntaxChecker): + (JSC::SyntaxChecker::createSourceElements): + (JSC::SyntaxChecker::makeFunctionCallNode): + (JSC::SyntaxChecker::appendToComma): + (JSC::SyntaxChecker::createCommaExpr): + (JSC::SyntaxChecker::makeAssignNode): + (JSC::SyntaxChecker::makePrefixNode): + (JSC::SyntaxChecker::makePostfixNode): + (JSC::SyntaxChecker::makeTypeOfNode): + (JSC::SyntaxChecker::makeDeleteNode): + (JSC::SyntaxChecker::makeNegateNode): + (JSC::SyntaxChecker::makeBitwiseNotNode): + (JSC::SyntaxChecker::createLogicalNot): + (JSC::SyntaxChecker::createUnaryPlus): + (JSC::SyntaxChecker::createVoid): + (JSC::SyntaxChecker::thisExpr): + (JSC::SyntaxChecker::createResolve): + (JSC::SyntaxChecker::createObjectLiteral): + (JSC::SyntaxChecker::createArray): + (JSC::SyntaxChecker::createNumberExpr): + (JSC::SyntaxChecker::createString): + (JSC::SyntaxChecker::createBoolean): + (JSC::SyntaxChecker::createNull): + (JSC::SyntaxChecker::createBracketAccess): + (JSC::SyntaxChecker::createDotAccess): + (JSC::SyntaxChecker::createRegex): + (JSC::SyntaxChecker::createNewExpr): + (JSC::SyntaxChecker::createConditionalExpr): + (JSC::SyntaxChecker::createAssignResolve): + (JSC::SyntaxChecker::createFunctionExpr): + (JSC::SyntaxChecker::createFunctionBody): + (JSC::SyntaxChecker::createArguments): + (JSC::SyntaxChecker::createArgumentsList): + (JSC::SyntaxChecker::createProperty): + (JSC::SyntaxChecker::createPropertyList): + (JSC::SyntaxChecker::createElementList): + (JSC::SyntaxChecker::createFormalParameterList): + (JSC::SyntaxChecker::createClause): + (JSC::SyntaxChecker::createClauseList): + (JSC::SyntaxChecker::setUsesArguments): + (JSC::SyntaxChecker::createFuncDeclStatement): + (JSC::SyntaxChecker::createBlockStatement): + (JSC::SyntaxChecker::createExprStatement): + (JSC::SyntaxChecker::createIfStatement): + (JSC::SyntaxChecker::createForLoop): + (JSC::SyntaxChecker::createForInLoop): + (JSC::SyntaxChecker::createEmptyStatement): + (JSC::SyntaxChecker::createVarStatement): + (JSC::SyntaxChecker::createReturnStatement): + (JSC::SyntaxChecker::createBreakStatement): + (JSC::SyntaxChecker::createContinueStatement): + (JSC::SyntaxChecker::createTryStatement): + (JSC::SyntaxChecker::createSwitchStatement): + (JSC::SyntaxChecker::createWhileStatement): + (JSC::SyntaxChecker::createWithStatement): + (JSC::SyntaxChecker::createDoWhileStatement): + (JSC::SyntaxChecker::createLabelStatement): + (JSC::SyntaxChecker::createThrowStatement): + (JSC::SyntaxChecker::createDebugger): + (JSC::SyntaxChecker::createConstStatement): + (JSC::SyntaxChecker::appendConstDecl): + (JSC::SyntaxChecker::createGetterOrSetterProperty): + (JSC::SyntaxChecker::appendStatement): + (JSC::SyntaxChecker::addVar): + (JSC::SyntaxChecker::combineCommaNodes): + (JSC::SyntaxChecker::evalCount): + (JSC::SyntaxChecker::appendBinaryExpressionInfo): + (JSC::SyntaxChecker::operatorStackPop): + * runtime/JSGlobalData.h: + * wtf/Platform.h: + * wtf/ThreadSpecific.h: + (WTF::T): + +2010-06-23 Jedrzej Nowacki <jedrzej.nowacki@nokia.com> + + Reviewed by Simon Hausmann. + + Optimization of the QScriptValuePrivate. + + Patch change only internals of the QScriptValuePrivate. + Most of the QScriptValuePrivate's attributes were moved + into an union. + + [Qt] Optimization of the QScriptVAluePrivate. + https://bugs.webkit.org/show_bug.cgi?id=40415 + + * qt/api/qscriptengine_p.cpp: + (QScriptEnginePrivate::globalObject): + * qt/api/qscriptvalue_p.h: + (QScriptValuePrivate::): + (QScriptValuePrivate::~QScriptValuePrivate): + (QScriptValuePrivate::QScriptValuePrivate): + (QScriptValuePrivate::toString): + (QScriptValuePrivate::toNumber): + (QScriptValuePrivate::toBool): + (QScriptValuePrivate::toObject): + (QScriptValuePrivate::equals): + (QScriptValuePrivate::strictlyEquals): + (QScriptValuePrivate::assignEngine): + (QScriptValuePrivate::operator JSValueRef): + (QScriptValuePrivate::operator JSObjectRef): + (QScriptValuePrivate::refinedJSValue): + +2010-06-23 Kwang Yul Seo <skyul@company100.net> + + Reviewed by Oliver Hunt. + + [GTK] Implement ThreadSpecific with glib + https://bugs.webkit.org/show_bug.cgi?id=39829 + + Implement ThreadSpecific with glib's GStaticPrivate. + This patch makes it possible to build GTK port without pthread. + + * wtf/ThreadSpecific.h: + (WTF::::ThreadSpecific): + (WTF::::~ThreadSpecific): + (WTF::::get): + (WTF::::set): + (WTF::::destroy): + +2010-06-23 Leandro Pereira <leandro@profusion.mobi> + + Unreviewed build fix. + + * CMakeLists.txt: Add runtime/RegExpCache.cpp. + +2010-06-22 Renata Hodovan <hodovan@inf.u-szeged.hu> + + Reviewed by Geoffrey Garen. + + Adding regular expression caching to JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=38142 + + The cache is based on Round Robin eviction policy, and + can cache at most 256 character long regular expressions, + and at most 256 of them. These values can be changed at compile time. + + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.pro: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecompiler/NodesCodegen.cpp: + (JSC::RegExpNode::emitBytecode): + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + (JSC::JSGlobalData::~JSGlobalData): + * runtime/JSGlobalData.h: + (JSC::JSGlobalData::regExpCache): + * runtime/RegExpCache.cpp: Added. + (JSC::RegExpCache::lookupOrCreate): + (JSC::RegExpCache::create): + (JSC::RegExpCache::RegExpCache): + * runtime/RegExpCache.h: Added. + * runtime/RegExpConstructor.cpp: + (JSC::constructRegExp): + * runtime/RegExpKey.h: Added. + (JSC::RegExpKey::RegExpKey): + (JSC::RegExpKey::getFlagsValue): + (WTF::operator==): + (WTF::): + * runtime/RegExpPrototype.cpp: + (JSC::regExpProtoFuncCompile): + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncMatch): + (JSC::stringProtoFuncSearch): + +2010-06-22 Gabor Loki <loki@webkit.org> + + Reviewed by Geoffrey Garen. + + Add native call support for ARM and Thumb-2 JIT. + https://bugs.webkit.org/show_bug.cgi?id=40231 + + * jit/JITOpcodes.cpp: + (JSC::JIT::privateCompileCTINativeCall): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::privateCompileCTINativeCall): + * wtf/Platform.h: + +2010-06-21 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoffrey Garen. + + Make JSC more resilient in the face of parse failures + https://bugs.webkit.org/show_bug.cgi?id=40951 + + A number of recent bugs have occurred due to issues like miscounting + BOMs, etc which lead to interesting crashes later on. Adding this + logic hardens JSC in the face of these errors, and has no impact on + performance (32bit jit actually gets 0.7% faster but I put that down + to cache effects). + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::reparseForExceptionInfoIfNecessary): + (JSC::CodeBlock::lineNumberForBytecodeOffset): + (JSC::CodeBlock::expressionRangeForBytecodeOffset): + (JSC::CodeBlock::getByIdExceptionInfoForBytecodeOffset): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::bytecodeOffset): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + (JSC::Interpreter::prepareForRepeatCall): + (JSC::Interpreter::privateExecute): + * jit/JITOpcodes.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * runtime/ArrayPrototype.cpp: + (JSC::isNumericCompareFunction): + * runtime/Executable.cpp: + (JSC::FunctionExecutable::compileForCall): + (JSC::FunctionExecutable::compileForConstruct): + (JSC::FunctionExecutable::generateJITCodeForCall): + (JSC::FunctionExecutable::generateJITCodeForConstruct): + (JSC::FunctionExecutable::reparseExceptionInfo): + (JSC::EvalExecutable::reparseExceptionInfo): + * runtime/Executable.h: + (JSC::FunctionExecutable::bytecodeForCall): + (JSC::FunctionExecutable::bytecodeForConstruct): + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::numericCompareFunction): + +2010-06-21 John Sullivan <sullivan@apple.com> + + Reviewed by Adam Roben. + + RetainPtr can't be used in HashMaps or HashSets + <https://bugs.webkit.org/show_bug.cgi?id=40938> + + Added hashing knowledge similar to that in COMPtr.h. + + * wtf/RetainPtr.h: + (WTF::RetainPtr::RetainPtr): + New function, copied from COMPtr.h but for the type change. + (WTF::RetainPtr::isHashTableDeletedValue): + Ditto. + (WTF::RetainPtr::hashTableDeletedValue): + Ditto. + Added template code for HashTraits and PtrHash copied from COMPtr.h but for the type change. + The only difference is that constructDeletedValue() matches the RefPtr implementation (in HashTraits.h) + rather than the COMPtr implementation. + +2010-06-19 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoffrey Garen. + + Need to ensure that we grow the RegisterFile when creating a callframe for host code + https://bugs.webkit.org/show_bug.cgi?id=40858 + <rdar://problem/8108986> + + In the past the use of the callframe in hostcode was much more + limited. Now that we expect the callframe to always be valid + we need to grow the RegisterFile so that this is actually the + case. In this particular case the problem was failing to grow + the registerfile could lead to a callframe that extended beyond + RegisterFiler::end(), so vm re-entry would clobber the callframe + other scenarios could also lead to badness. + + I was unable to construct a simple testcase to trigger badness, + and any such testcase would be so dependent on exact vm stack + layout that it would be unlikely to work as a testcase following + any callframe or register allocation changes anyway. + + Thankfully the new assertion I added should help to catch these + failures in future, and triggers on a couple of tests currently. + + * interpreter/CallFrame.cpp: + (JSC::CallFrame::registerFile): + * interpreter/CallFrame.h: + (JSC::ExecState::init): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + +2010-06-21 Satish Sampath <satish@chromium.org> + + Reviewed by Steve Block. + + Speech Input Patch 0: Added compilation argument to conditionally compile pending patches. + https://bugs.webkit.org/show_bug.cgi?id=40878 + + * Configurations/FeatureDefines.xcconfig: + +2010-06-21 Kwang Yul Seo <skyul@company100.net> + + Reviewed by Kent Tamura. + + [BREWMP] Use global new/delete operator overloading with USE_SYSTEM_MALLOC=1 + https://bugs.webkit.org/show_bug.cgi?id=40653 + + Currently, other ports do not use global new/delete operator overloading + when USE_SYSTEM_MALLOC=1. Brew MP uses system malloc, but it needs to enable + "global fastMalloc new" because the default new/delete causes crash on device. + We need to replace them with Brew MP's MALLOC/FREE. + + * wtf/FastMalloc.h: + +2010-06-18 Jocelyn Turcotte <jocelyn.turcotte@nokia.com> + + Reviewed by Simon Hausmann. + + [Qt] Work around a build problem with libjscore on Symbian. + https://bugs.webkit.org/show_bug.cgi?id=40840 + + Sbsv2 sometimes have problems with debug/release configuration + determination causing QtWebKit in release to try linking with the debug + JavaScriptCore static library. This patch limit the jscore/jscored + r58306 fix necessary for mac builds only to the mac platform to prevent the + different name problem. + + The real fix would be to fix qmake or the toolchain, this patch might + help meanwhile. + + * JavaScriptCore.pri: + +2010-06-21 Patrick Gansterer <paroga@paroga.com> + + Reviewed by Kent Tamura. + + Buildfix after r61338. + https://bugs.webkit.org/show_bug.cgi?id=40888 + + roundUpAllocationSize is needed in RegisterFile.h. + + * jit/ExecutableAllocator.h: + +2010-06-19 Kwang Yul Seo <skyul@company100.net> + + Reviewed by Darin Adler. + + Include <string.h> in StringExtras.h + https://bugs.webkit.org/show_bug.cgi?id=40808 + + Without string.h, RVCT 2.2 can't compile StringExtras.h. + It can't find strlen and strncmp. + + * wtf/StringExtras.h: + +2010-06-19 Thiago Macieira <thiago.macieira@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + Don't use __attribute__((may_alias)) with the Intel compiler, + as it doesn't understand it. + + * wtf/Vector.h: + +2010-06-19 Thiago Macieira <thiago.macieira@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + Fix compilation with the Intel C++ compiler (11.1.072). + + Like RVCT, label pointers must be void*, not const void*. + + * bytecode/Opcode.h: + +2010-06-19 Thiago Macieira <thiago.macieira@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + Add the WTF_COMPILER_INTEL for when the Intel compiler is used + for building. Usually, the Intel compiler masquerades as + another compiler in the system and gets away with it, but some + times specific fixes are required (such as when using language + extensions). + + * wtf/Platform.h: + +2010-06-18 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoffrey Garen. + + Incorrect handling of multiple BOMs scattered through a file. + https://bugs.webkit.org/show_bug.cgi?id=40865 + + When determining the offset of open and close braces in a source + with BOMs we were finishing our count early as we failed to account + for BOMs prior to the open/close brace positions effecting those + positions. + + * parser/Lexer.cpp: + (JSC::Lexer::sourceCode): + +2010-06-17 Oliver Hunt <oliver@apple.com> + + Reviewed by Sam Weinig. + + Don't throw away exception information for functions that use exceptions + https://bugs.webkit.org/show_bug.cgi?id=40786 + + Simple patch to stop JSC from throwing away the exception information + of a function that uses "exceptiony" features like try and throw. This + is a speed up for catching expressions but it's difficult to quantify as + the old cost of reparsing is amortised over all exceptions caught in the + effected function. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::reparseForExceptionInfoIfNecessary): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::generate): + (JSC::BytecodeGenerator::emitCatch): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::emitThrow): + +2010-06-18 Anders Carlsson <andersca@apple.com> + + Reviewed by Sam Weinig. + + Add PlatformStrategies and PluginStrategy classes. + https://bugs.webkit.org/show_bug.cgi?id=40850 + + * wtf/Platform.h: + +2010-06-18 Leandro Pereira <leandro@profusion.mobi> + + [EFL] Unreviewed build fix. + + * wtf/CMakeLists.txt: Add MD5.cpp. + +2010-06-17 Shu Chang <chang.shu@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Fix the link error on symbian with ENABLE_JIT=0. + 1. Add "#if ENABLE(JIT)" in the header file; + 2. Put feature enable/disable logic to a common.pri so + that both JavaScriptCore.pri and WebCore.pri can share. + + https://bugs.webkit.org/show_bug.cgi?id=40780 + + * JavaScriptCore.pri: + * jit/ExecutableAllocator.h: + +2010-06-17 Darin Adler <darin@apple.com> + + Reviewed by Sam Weinig. + + Use adoptRef and create functions in more code paths + https://bugs.webkit.org/show_bug.cgi?id=40760 + + * API/JSClassRef.h: Removed unneeded include of RefCounted.h. + * API/JSWeakObjectMapRefPrivate.cpp: Ditto. + + * bytecode/CodeBlock.h: + (JSC::FunctionCodeBlock::FunctionCodeBlock): Use the + SharedSymbolTable::create function instead of calling new directly. + + * runtime/SymbolTable.h: Added a create function to the SharedSymbolTable + class and made the constructor private. + +2010-06-17 Mark Brand <mabrand@mabrand.nl> + + Reviewed by Simon Hausmann. + + [Qt] use "win32-g++*" scope to match all MinGW makespecs + + The scope "win32-g++" comes from the name of the makespec. However, it + is frequently used to check for MinGW. This works fine as long as + win32-g++ is the only makespec for MinGW. Now we need the wildcard + to cover "win32-g++-cross" as well. + + * JavaScriptCore.pro: + +2010-06-16 Darin Adler <darin@apple.com> + + Reviewed by David Levin. + + Deploy adoptRef in more places, including all HTML and MathML elements + https://bugs.webkit.org/show_bug.cgi?id=39941 + + * wtf/ThreadSafeShared.h: Made the constructor protected and removed the + unneeded support for initial reference counts other than 1. + +2010-06-16 Peter Varga <pvarga@inf.u-szeged.hu> + + Reviewed by Geoffrey Garen. + + Store matchBegin directly in the array of output instead of the stack. + https://bugs.webkit.org/show_bug.cgi?id=38988 + + * yarr/RegexJIT.cpp: + (JSC::Yarr::RegexGenerator::generateDisjunction): + (JSC::Yarr::RegexGenerator::generate): + +2010-06-15 Anders Carlsson <andersca@apple.com> + + Reviewed by Sam Weinig. + + Make JavaScriptCore build with clang++. + + * jit/JITInlineMethods.h: + (JSC::JIT::emitPutVirtualRegister): + Explicitly cast to an int. + + * yarr/RegexCompiler.cpp: + (JSC::Yarr::compileRegex): + Return 0 instead of false. + +2010-06-15 Adam Roben <aroben@apple.com> + + Make WebCore's and JavaScriptCore's DerivedSources available for debugging in production builds + + Fixes <http://webkit.org/b/40626> <rdar://problem/8094205>. + + Reviewed by Sam Weinig. + + * JavaScriptCore.vcproj/JavaScriptCore.make: Copy the contents of + JavaScriptCore's DerivedSources directory to + AppleInternal/Sources/JavaScriptCore. + +2010-06-15 Gabor Loki <loki@webkit.org> + + Rubber-stamped by Eric Seidel. + + Fix invalid access to non-static data member warning in JITPropertyAccess32_64 on ARM + https://bugs.webkit.org/show_bug.cgi?id=40423 + + Using OBJECT_OFFSETOF macro instead of objectof to bypass access to + non-static data member warning. + + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::privateCompilePutByIdTransition): + 2010-06-11 Eric Seidel <eric@webkit.org> Reviewed by Adam Barth. diff --git a/JavaScriptCore/Configurations/FeatureDefines.xcconfig b/JavaScriptCore/Configurations/FeatureDefines.xcconfig index 5b52793..08d9ef9 100644 --- a/JavaScriptCore/Configurations/FeatureDefines.xcconfig +++ b/JavaScriptCore/Configurations/FeatureDefines.xcconfig @@ -57,6 +57,7 @@ ENABLE_GEOLOCATION = ENABLE_GEOLOCATION; ENABLE_ICONDATABASE = ENABLE_ICONDATABASE; ENABLE_IMAGE_RESIZER = ; ENABLE_INDEXED_DATABASE = ; +ENABLE_INPUT_SPEECH = ; ENABLE_JAVASCRIPT_DEBUGGER = ENABLE_JAVASCRIPT_DEBUGGER; ENABLE_MATHML = ; ENABLE_METER_TAG = ENABLE_METER_TAG; @@ -81,4 +82,4 @@ ENABLE_XHTMLMP = ; ENABLE_XPATH = ENABLE_XPATH; ENABLE_XSLT = ENABLE_XSLT; -FEATURE_DEFINES = $(ENABLE_3D_CANVAS) $(ENABLE_3D_RENDERING) $(ENABLE_BLOB_SLICE) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CLIENT_BASED_GEOLOCATION) $(ENABLE_DATABASE) $(ENABLE_DATAGRID) $(ENABLE_DATALIST) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DOM_STORAGE) $(ENABLE_EVENTSOURCE) $(ENABLE_FILTERS) $(ENABLE_FILE_READER) $(ENABLE_FILE_WRITER) $(ENABLE_GEOLOCATION) $(ENABLE_ICONDATABASE) $(ENABLE_IMAGE_RESIZER) $(ENABLE_INDEXED_DATABASE) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_MATHML) $(ENABLE_METER_TAG) $(ENABLE_NOTIFICATIONS) $(ENABLE_OFFLINE_WEB_APPLICATIONS) $(ENABLE_PROGRESS_TAG) $(ENABLE_RUBY) $(ENABLE_SANDBOX) $(ENABLE_SHARED_WORKERS) $(ENABLE_SVG) $(ENABLE_SVG_ANIMATION) $(ENABLE_SVG_AS_IMAGE) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_SVG_FOREIGN_OBJECT) $(ENABLE_SVG_USE) $(ENABLE_VIDEO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WML) $(ENABLE_WORKERS) $(ENABLE_XHTMLMP) $(ENABLE_XPATH) $(ENABLE_XSLT); +FEATURE_DEFINES = $(ENABLE_3D_CANVAS) $(ENABLE_3D_RENDERING) $(ENABLE_BLOB_SLICE) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CLIENT_BASED_GEOLOCATION) $(ENABLE_DATABASE) $(ENABLE_DATAGRID) $(ENABLE_DATALIST) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DOM_STORAGE) $(ENABLE_EVENTSOURCE) $(ENABLE_FILTERS) $(ENABLE_FILE_READER) $(ENABLE_FILE_WRITER) $(ENABLE_GEOLOCATION) $(ENABLE_ICONDATABASE) $(ENABLE_IMAGE_RESIZER) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_SPEECH) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_MATHML) $(ENABLE_METER_TAG) $(ENABLE_NOTIFICATIONS) $(ENABLE_OFFLINE_WEB_APPLICATIONS) $(ENABLE_PROGRESS_TAG) $(ENABLE_RUBY) $(ENABLE_SANDBOX) $(ENABLE_SHARED_WORKERS) $(ENABLE_SVG) $(ENABLE_SVG_ANIMATION) $(ENABLE_SVG_AS_IMAGE) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_SVG_FOREIGN_OBJECT) $(ENABLE_SVG_USE) $(ENABLE_VIDEO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WML) $(ENABLE_WORKERS) $(ENABLE_XHTMLMP) $(ENABLE_XPATH) $(ENABLE_XSLT); diff --git a/JavaScriptCore/Configurations/Version.xcconfig b/JavaScriptCore/Configurations/Version.xcconfig index 6f999af..f775a54 100644 --- a/JavaScriptCore/Configurations/Version.xcconfig +++ b/JavaScriptCore/Configurations/Version.xcconfig @@ -22,7 +22,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. MAJOR_VERSION = 534; -MINOR_VERSION = 1; +MINOR_VERSION = 2; TINY_VERSION = 0; FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION); diff --git a/JavaScriptCore/GNUmakefile.am b/JavaScriptCore/GNUmakefile.am index a9c19c6..957c743 100644 --- a/JavaScriptCore/GNUmakefile.am +++ b/JavaScriptCore/GNUmakefile.am @@ -381,6 +381,9 @@ javascriptcore_sources += \ JavaScriptCore/bytecompiler/LabelScope.h \ JavaScriptCore/debugger/Debugger.cpp \ JavaScriptCore/debugger/Debugger.h \ + JavaScriptCore/parser/ASTBuilder.h \ + JavaScriptCore/parser/JSParser.cpp \ + JavaScriptCore/parser/JSParser.h \ JavaScriptCore/parser/Lexer.cpp \ JavaScriptCore/parser/Lexer.h \ JavaScriptCore/parser/NodeConstructors.h \ @@ -394,6 +397,7 @@ javascriptcore_sources += \ JavaScriptCore/parser/ResultType.h \ JavaScriptCore/parser/SourceCode.h \ JavaScriptCore/parser/SourceProvider.h \ + JavaScriptCore/parser/SyntaxChecker.h \ JavaScriptCore/runtime/ArgList.cpp \ JavaScriptCore/runtime/ArgList.h \ JavaScriptCore/runtime/Arguments.cpp \ @@ -515,8 +519,11 @@ javascriptcore_sources += \ JavaScriptCore/runtime/PutPropertySlot.h \ JavaScriptCore/runtime/RegExp.cpp \ JavaScriptCore/runtime/RegExp.h \ + JavaScriptCore/runtime/RegExpCache.cpp \ + JavaScriptCore/runtime/RegExpCache.h \ JavaScriptCore/runtime/RegExpConstructor.cpp \ JavaScriptCore/runtime/RegExpConstructor.h \ + JavaScriptCore/runtime/RegExpKey.h \ JavaScriptCore/runtime/RegExpMatchesArray.h \ JavaScriptCore/runtime/RegExpObject.cpp \ JavaScriptCore/runtime/RegExpObject.h \ diff --git a/JavaScriptCore/JavaScriptCore.gypi b/JavaScriptCore/JavaScriptCore.gypi index c54ff17..066e1ff 100644 --- a/JavaScriptCore/JavaScriptCore.gypi +++ b/JavaScriptCore/JavaScriptCore.gypi @@ -130,6 +130,9 @@ 'jsc.cpp', 'os-win32/stdbool.h', 'os-win32/stdint.h', + 'parser/ASTBuilder.h', + 'parser/JSParser.cpp', + 'parser/JSParser.h', 'parser/Lexer.cpp', 'parser/Lexer.h', 'parser/NodeConstructors.h', @@ -143,6 +146,7 @@ 'parser/ResultType.h', 'parser/SourceCode.h', 'parser/SourceProvider.h', + 'parser/SyntaxChecker.h', 'pcre/pcre.h', 'pcre/pcre_compile.cpp', 'pcre/pcre_exec.cpp', @@ -305,8 +309,11 @@ 'runtime/PutPropertySlot.h', 'runtime/RegExp.cpp', 'runtime/RegExp.h', + 'runtime/RegExpCache.cpp', + 'runtime/RegExpCache.h', 'runtime/RegExpConstructor.cpp', 'runtime/RegExpConstructor.h', + 'runtime/RegExpKey.h', 'runtime/RegExpMatchesArray.h', 'runtime/RegExpObject.cpp', 'runtime/RegExpObject.h', diff --git a/JavaScriptCore/JavaScriptCore.pri b/JavaScriptCore/JavaScriptCore.pri index 09dba2f..8ef9b30 100644 --- a/JavaScriptCore/JavaScriptCore.pri +++ b/JavaScriptCore/JavaScriptCore.pri @@ -1,14 +1,17 @@ # JavaScriptCore - Qt4 build info + +include(../common.pri) + VPATH += $$PWD -!CONFIG(release, debug|release) { - # Output in JavaScriptCore/<config> - JAVASCRIPTCORE_DESTDIR = debug - # Use a config-specific target to prevent parallel builds file clashes on Mac - JAVASCRIPTCORE_TARGET = jscored -} else { - JAVASCRIPTCORE_DESTDIR = release - JAVASCRIPTCORE_TARGET = jscore -} + +# Use a config-specific target to prevent parallel builds file clashes on Mac +mac: CONFIG(debug, debug|release): JAVASCRIPTCORE_TARGET = jscored +else: JAVASCRIPTCORE_TARGET = jscore + +# Output in JavaScriptCore/<config> +CONFIG(debug, debug|release) : JAVASCRIPTCORE_DESTDIR = debug +else: JAVASCRIPTCORE_DESTDIR = release + CONFIG(standalone_package) { isEmpty(JSC_GENERATED_SOURCES_DIR):JSC_GENERATED_SOURCES_DIR = $$PWD/generated } else { @@ -51,9 +54,6 @@ win32-*: DEFINES += _HAS_TR1=0 DEFINES += BUILDING_QT__ BUILDING_JavaScriptCore BUILDING_WTF -contains(JAVASCRIPTCORE_JIT,yes): DEFINES+=ENABLE_JIT=1 -contains(JAVASCRIPTCORE_JIT,no): DEFINES+=ENABLE_JIT=0 - wince* { INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/ce-compat DEFINES += WINCEBASIC diff --git a/JavaScriptCore/JavaScriptCore.pro b/JavaScriptCore/JavaScriptCore.pro index a3d8358..8ee4f09 100644 --- a/JavaScriptCore/JavaScriptCore.pro +++ b/JavaScriptCore/JavaScriptCore.pro @@ -43,7 +43,7 @@ CONFIG(QTDIR_build) { } # Pick up 3rdparty libraries from INCLUDE/LIB just like with MSVC -win32-g++ { +win32-g++* { TMPPATH = $$quote($$(INCLUDE)) QMAKE_INCDIR_POST += $$split(TMPPATH,";") TMPPATH = $$quote($$(LIB)) @@ -109,6 +109,7 @@ SOURCES += \ jit/JITPropertyAccess32_64.cpp \ jit/JITStubs.cpp \ jit/ThunkGenerators.cpp \ + parser/JSParser.cpp \ parser/Lexer.cpp \ parser/Nodes.cpp \ parser/ParserArena.cpp \ @@ -191,6 +192,7 @@ SOURCES += \ runtime/RegExp.cpp \ runtime/RegExpObject.cpp \ runtime/RegExpPrototype.cpp \ + runtime/RegExpCache.cpp \ runtime/RopeImpl.cpp \ runtime/ScopeChain.cpp \ runtime/SmallStrings.cpp \ diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.make b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.make index 806894a..4c47ac6 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.make +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.make @@ -31,3 +31,5 @@ install: xcopy "$(OBJROOT)\include\*" "$(DSTROOT)\AppleInternal\include\" /e/v/i/h/y xcopy "$(OBJROOT)\lib\*" "$(DSTROOT)\AppleInternal\lib\" /e/v/i/h/y xcopy "$(OBJROOT)\bin\JavaScriptCore.resources\*" "$(DSTROOT)\AppleInternal\bin\JavaScriptCore.resources" /e/v/i/h/y + -mkdir "$(DSTROOT)\AppleInternal\Sources\JavaScriptCore" + xcopy "$(OBJROOT)\obj\JavaScriptCore\DerivedSources\*" "$(DSTROOT)\AppleInternal\Sources\WebCore" /e/v/i/h/y diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj index effce51..8117f78 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -1089,6 +1089,14 @@ >
</File>
<File
+ RelativePath="..\..\runtime\RegExpCache.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\runtime\RegExpCache.h"
+ >
+ </File>
+ <File
RelativePath="..\..\runtime\RegExpConstructor.cpp"
>
</File>
@@ -1097,6 +1105,10 @@ >
</File>
<File
+ RelativePath="..\..\runtime\RegExpKey.h"
+ >
+ </File>
+ <File
RelativePath="..\..\runtime\RegExpMatchesArray.h"
>
</File>
@@ -1789,6 +1801,18 @@ Name="parser"
>
<File
+ RelativePath="..\..\parser\ASTBuilder.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\parser\JSParser.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\parser\JSParser.h"
+ >
+ </File>
+ <File
RelativePath="..\..\parser\Lexer.cpp"
>
</File>
@@ -1840,6 +1864,10 @@ RelativePath="..\..\parser\SourceProvider.h"
>
</File>
+ <File
+ RelativePath="..\..\parser\SyntaxChecker.h"
+ >
+ </File>
</Filter>
<Filter
Name="Derived Sources"
diff --git a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 3b448c5..bc58f5d 100644 --- a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -293,6 +293,9 @@ 969A079B0ED1D3AE00F1F681 /* Opcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 969A07950ED1D3AE00F1F681 /* Opcode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 96DD73790F9DA3100027FBCC /* VMTags.h in Headers */ = {isa = PBXBuildFile; fileRef = 96DD73780F9DA3100027FBCC /* VMTags.h */; settings = {ATTRIBUTES = (Private, ); }; }; 971EDEA61169E0D3005E4262 /* Terminator.h in Headers */ = {isa = PBXBuildFile; fileRef = 97F6903A1169DF7F00A6BB46 /* Terminator.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A1712B3B11C7B212007A5315 /* RegExpCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1712B3A11C7B212007A5315 /* RegExpCache.cpp */; }; + A1712B3F11C7B228007A5315 /* RegExpCache.h in Headers */ = {isa = PBXBuildFile; fileRef = A1712B3E11C7B228007A5315 /* RegExpCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A1712B4111C7B235007A5315 /* RegExpKey.h in Headers */ = {isa = PBXBuildFile; fileRef = A1712B4011C7B235007A5315 /* RegExpKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; A71236E51195F33C00BD2174 /* JITOpcodes32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A71236E41195F33C00BD2174 /* JITOpcodes32_64.cpp */; }; A72700900DAC6BBC00E548D7 /* JSNotAnObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A72700780DAC605600E548D7 /* JSNotAnObject.cpp */; }; A72701B90DADE94900E548D7 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; }; @@ -313,6 +316,10 @@ A782F1A50EEC9FA20036273F /* ExecutableAllocatorPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A782F1A40EEC9FA20036273F /* ExecutableAllocatorPosix.cpp */; }; A783A0D111A36DCA00563D20 /* JSObjectWithGlobalObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A783A0D011A36DCA00563D20 /* JSObjectWithGlobalObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; A783A2AB11A5BE8400563D20 /* JSObjectWithGlobalObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A783A2AA11A5BE8400563D20 /* JSObjectWithGlobalObject.cpp */; }; + A784A26111D16622005776AC /* ASTBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A7EE7411B98B8D0065A14F /* ASTBuilder.h */; }; + A784A26211D16622005776AC /* JSParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7A7EE7511B98B8D0065A14F /* JSParser.cpp */; }; + A784A26311D16622005776AC /* JSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A7EE7611B98B8D0065A14F /* JSParser.h */; }; + A784A26411D16622005776AC /* SyntaxChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A7EE7711B98B8D0065A14F /* SyntaxChecker.h */; }; A791EF280F11E07900AE1F68 /* JSByteArray.h in Headers */ = {isa = PBXBuildFile; fileRef = A791EF260F11E07900AE1F68 /* JSByteArray.h */; settings = {ATTRIBUTES = (Private, ); }; }; A791EF290F11E07900AE1F68 /* JSByteArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A791EF270F11E07900AE1F68 /* JSByteArray.cpp */; }; A7A1F7AC0F252B3C00E184E2 /* ByteArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7A1F7AA0F252B3C00E184E2 /* ByteArray.cpp */; }; @@ -888,6 +895,9 @@ 969A09220ED1E09C00F1F681 /* Completion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Completion.cpp; sourceTree = "<group>"; }; 96DD73780F9DA3100027FBCC /* VMTags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMTags.h; sourceTree = "<group>"; }; 97F6903A1169DF7F00A6BB46 /* Terminator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Terminator.h; sourceTree = "<group>"; }; + A1712B3A11C7B212007A5315 /* RegExpCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegExpCache.cpp; sourceTree = "<group>"; }; + A1712B3E11C7B228007A5315 /* RegExpCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpCache.h; sourceTree = "<group>"; }; + A1712B4011C7B235007A5315 /* RegExpKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpKey.h; sourceTree = "<group>"; }; A71236E41195F33C00BD2174 /* JITOpcodes32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITOpcodes32_64.cpp; sourceTree = "<group>"; }; A718F61A11754A21002465A7 /* RegExpJitTables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpJitTables.h; sourceTree = "<group>"; }; A718F8211178EB4B002465A7 /* create_regex_tables */ = {isa = PBXFileReference; explicitFileType = text.script.python; fileEncoding = 4; path = create_regex_tables; sourceTree = "<group>"; }; @@ -915,6 +925,10 @@ A79EDB0811531CD60019E912 /* JSObjectRefPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSObjectRefPrivate.h; sourceTree = "<group>"; }; A7A1F7AA0F252B3C00E184E2 /* ByteArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ByteArray.cpp; sourceTree = "<group>"; }; A7A1F7AB0F252B3C00E184E2 /* ByteArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByteArray.h; sourceTree = "<group>"; }; + A7A7EE7411B98B8D0065A14F /* ASTBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTBuilder.h; sourceTree = "<group>"; }; + A7A7EE7511B98B8D0065A14F /* JSParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSParser.cpp; sourceTree = "<group>"; }; + A7A7EE7611B98B8D0065A14F /* JSParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSParser.h; sourceTree = "<group>"; }; + A7A7EE7711B98B8D0065A14F /* SyntaxChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyntaxChecker.h; sourceTree = "<group>"; }; A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutableAllocator.h; sourceTree = "<group>"; }; A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutableAllocator.cpp; sourceTree = "<group>"; }; A7C1E8C8112E701C00A37F98 /* JITPropertyAccess32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITPropertyAccess32_64.cpp; sourceTree = "<group>"; }; @@ -1516,7 +1530,10 @@ 7E39D8370EC3A388003AF11A /* parser */ = { isa = PBXGroup; children = ( + A7A7EE7411B98B8D0065A14F /* ASTBuilder.h */, 933A3499038AE7C6008635CE /* Grammar.y */, + A7A7EE7511B98B8D0065A14F /* JSParser.cpp */, + A7A7EE7611B98B8D0065A14F /* JSParser.h */, 93F1981A08245AAE001E9ABC /* Keywords.table */, F692A8650255597D01FF60F7 /* Lexer.cpp */, F692A8660255597D01FF60F7 /* Lexer.h */, @@ -1531,6 +1548,7 @@ 869EBCB60E8C6D4A008722CC /* ResultType.h */, 65E866EE0DD59AFA00A2B2A1 /* SourceCode.h */, 65E866ED0DD59AFA00A2B2A1 /* SourceProvider.h */, + A7A7EE7711B98B8D0065A14F /* SyntaxChecker.h */, ); path = parser; sourceTree = "<group>"; @@ -1538,6 +1556,9 @@ 7EF6E0BB0EB7A1EC0079AFAF /* runtime */ = { isa = PBXGroup; children = ( + A1712B4011C7B235007A5315 /* RegExpKey.h */, + A1712B3E11C7B228007A5315 /* RegExpCache.h */, + A1712B3A11C7B212007A5315 /* RegExpCache.cpp */, BCF605110E203EF800B9A64D /* ArgList.cpp */, BCF605120E203EF800B9A64D /* ArgList.h */, BC257DE50E1F51C50016B6C9 /* Arguments.cpp */, @@ -2166,6 +2187,11 @@ 86C568E211A213EE0007F7F0 /* MIPSAssembler.h in Headers */, A783A0D111A36DCA00563D20 /* JSObjectWithGlobalObject.h in Headers */, BC01D4F211A8F1FF00A54B2A /* JSZombie.h in Headers */, + A1712B3F11C7B228007A5315 /* RegExpCache.h in Headers */, + A1712B4111C7B235007A5315 /* RegExpKey.h in Headers */, + A784A26111D16622005776AC /* ASTBuilder.h in Headers */, + A784A26311D16622005776AC /* JSParser.h in Headers */, + A784A26411D16622005776AC /* SyntaxChecker.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2605,6 +2631,8 @@ 146FE51211A710430087AE66 /* JITCall32_64.cpp in Sources */, A783A2AB11A5BE8400563D20 /* JSObjectWithGlobalObject.cpp in Sources */, BC01D4F111A8F1FF00A54B2A /* JSZombie.cpp in Sources */, + A1712B3B11C7B212007A5315 /* RegExpCache.cpp in Sources */, + A784A26211D16622005776AC /* JSParser.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/JavaScriptCore/assembler/AssemblerBuffer.h b/JavaScriptCore/assembler/AssemblerBuffer.h index e2fb8a1..11e0df0 100644 --- a/JavaScriptCore/assembler/AssemblerBuffer.h +++ b/JavaScriptCore/assembler/AssemblerBuffer.h @@ -37,13 +37,14 @@ namespace JSC { class AssemblerBuffer { - static const int inlineCapacity = 256; + static const int inlineCapacity = 128 - sizeof(char*) - 2 * sizeof(int); public: AssemblerBuffer() : m_buffer(m_inlineBuffer) , m_capacity(inlineCapacity) , m_size(0) { + COMPILE_ASSERT(sizeof(AssemblerBuffer) == 128, AssemblerBuffer_should_be_128_bytes); } ~AssemblerBuffer() diff --git a/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h b/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h index b1c537e..599be14 100644 --- a/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h +++ b/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h @@ -190,6 +190,8 @@ public: void putIntWithConstantInt(uint32_t insn, uint32_t constant, bool isReusable = false) { + if (!m_numConsts) + m_maxDistance = maxPoolSize; flushIfNoSpaceFor(4, 4); m_loadOffsets.append(AssemblerBuffer::size()); @@ -279,7 +281,6 @@ private: m_loadOffsets.clear(); m_numConsts = 0; - m_maxDistance = maxPoolSize; } void flushIfNoSpaceFor(int nextInsnSize) diff --git a/JavaScriptCore/bytecode/CodeBlock.cpp b/JavaScriptCore/bytecode/CodeBlock.cpp index df3ca7b..30d101c 100644 --- a/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/JavaScriptCore/bytecode/CodeBlock.cpp @@ -1519,11 +1519,12 @@ void CodeBlock::markAggregate(MarkStack& markStack) m_functionDecls[i]->markAggregate(markStack); } -void CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame) +bool CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame) { if (m_exceptionInfo) - return; + return true; + ASSERT(!m_rareData || !m_rareData->m_exceptionHandlers.size()); ScopeChainNode* scopeChain = callFrame->scopeChain(); if (m_needsFullScopeChain) { ScopeChain sc(scopeChain); @@ -1538,6 +1539,7 @@ void CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame) } m_exceptionInfo.set(m_ownerExecutable->reparseExceptionInfo(m_globalData, scopeChain, this)); + return m_exceptionInfo; } HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset) @@ -1562,11 +1564,8 @@ int CodeBlock::lineNumberForBytecodeOffset(CallFrame* callFrame, unsigned byteco { ASSERT(bytecodeOffset < m_instructionCount); - reparseForExceptionInfoIfNecessary(callFrame); - ASSERT(m_exceptionInfo); - - if (!m_exceptionInfo->m_lineInfo.size()) - return m_ownerExecutable->source().firstLine(); // Empty function + if (!reparseForExceptionInfoIfNecessary(callFrame) || !m_exceptionInfo->m_lineInfo.size()) + return m_ownerExecutable->source().firstLine(); // Empty function or unable to reparse int low = 0; int high = m_exceptionInfo->m_lineInfo.size(); @@ -1587,11 +1586,9 @@ int CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned b { ASSERT(bytecodeOffset < m_instructionCount); - reparseForExceptionInfoIfNecessary(callFrame); - ASSERT(m_exceptionInfo); - - if (!m_exceptionInfo->m_expressionInfo.size()) { + if (!reparseForExceptionInfoIfNecessary(callFrame) || !m_exceptionInfo->m_expressionInfo.size()) { // We didn't think anything could throw. Apparently we were wrong. + // Alternatively something went wrong when trying to reparse startOffset = 0; endOffset = 0; divot = 0; @@ -1626,10 +1623,7 @@ bool CodeBlock::getByIdExceptionInfoForBytecodeOffset(CallFrame* callFrame, unsi { ASSERT(bytecodeOffset < m_instructionCount); - reparseForExceptionInfoIfNecessary(callFrame); - ASSERT(m_exceptionInfo); - - if (!m_exceptionInfo->m_getByIdExceptionInfo.size()) + if (!reparseForExceptionInfoIfNecessary(callFrame) || !m_exceptionInfo->m_getByIdExceptionInfo.size()) return false; int low = 0; diff --git a/JavaScriptCore/bytecode/CodeBlock.h b/JavaScriptCore/bytecode/CodeBlock.h index 27e56c6..590fe2e 100644 --- a/JavaScriptCore/bytecode/CodeBlock.h +++ b/JavaScriptCore/bytecode/CodeBlock.h @@ -351,7 +351,8 @@ namespace JSC { unsigned bytecodeOffset(CallFrame* callFrame, ReturnAddressPtr returnAddress) { - reparseForExceptionInfoIfNecessary(callFrame); + if (!reparseForExceptionInfoIfNecessary(callFrame)) + return 1; return binaryChop<CallReturnOffsetToBytecodeOffset, unsigned, getCallReturnOffset>(callReturnIndexVector().begin(), callReturnIndexVector().size(), getJITCode().offsetOf(returnAddress.value()))->bytecodeOffset; } @@ -521,7 +522,7 @@ namespace JSC { void printPutByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; #endif - void reparseForExceptionInfoIfNecessary(CallFrame*); + bool reparseForExceptionInfoIfNecessary(CallFrame*) WARN_UNUSED_RETURN; void createRareDataIfNecessary() { @@ -655,7 +656,7 @@ namespace JSC { // symbol table, so we just pass as a raw pointer with a ref count of 1. We then manually deref // in the destructor. FunctionCodeBlock(FunctionExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, bool isConstructor) - : CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, new SharedSymbolTable, isConstructor) + : CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, SharedSymbolTable::create().releaseRef(), isConstructor) { } ~FunctionCodeBlock() diff --git a/JavaScriptCore/bytecode/Opcode.h b/JavaScriptCore/bytecode/Opcode.h index 81fff99..f845a34 100644 --- a/JavaScriptCore/bytecode/Opcode.h +++ b/JavaScriptCore/bytecode/Opcode.h @@ -211,7 +211,7 @@ namespace JSC { #undef VERIFY_OPCODE_ID #if HAVE(COMPUTED_GOTO) -#if COMPILER(RVCT) +#if COMPILER(RVCT) || COMPILER(INTEL) typedef void* Opcode; #else typedef const void* Opcode; diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index 777e1e6..16ef357 100644 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -156,7 +156,7 @@ void BytecodeGenerator::generate() m_codeBlock->setIsNumericCompareFunction(instructions() == m_globalData->numericCompareFunction(m_scopeChain->globalObject()->globalExec())); #if !ENABLE(OPCODE_SAMPLING) - if (!m_regeneratingForExceptionInfo && (m_codeType == FunctionCode || m_codeType == EvalCode)) + if (!m_regeneratingForExceptionInfo && !m_usesExceptions && (m_codeType == FunctionCode || m_codeType == EvalCode)) m_codeBlock->clearExceptionInfo(); #endif @@ -219,6 +219,7 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* d , m_globalData(&scopeChain.globalObject()->globalExec()->globalData()) , m_lastOpcodeID(op_end) , m_emitNodeDepth(0) + , m_usesExceptions(false) , m_regeneratingForExceptionInfo(false) , m_codeBlockBeingRegeneratedFrom(0) { @@ -304,6 +305,7 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug , m_globalData(&scopeChain.globalObject()->globalExec()->globalData()) , m_lastOpcodeID(op_end) , m_emitNodeDepth(0) + , m_usesExceptions(false) , m_regeneratingForExceptionInfo(false) , m_codeBlockBeingRegeneratedFrom(0) { @@ -405,6 +407,7 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const Debugger* debugge , m_globalData(&scopeChain.globalObject()->globalExec()->globalData()) , m_lastOpcodeID(op_end) , m_emitNodeDepth(0) + , m_usesExceptions(false) , m_regeneratingForExceptionInfo(false) , m_codeBlockBeingRegeneratedFrom(0) { @@ -1842,6 +1845,7 @@ RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* RegisterID* BytecodeGenerator::emitCatch(RegisterID* targetRegister, Label* start, Label* end) { + m_usesExceptions = true; #if ENABLE(JIT) HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, CodeLocationLabel() }; #else diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/JavaScriptCore/bytecompiler/BytecodeGenerator.h index 8f0ce34..8b6ab77 100644 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -363,7 +363,12 @@ namespace JSC { RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target); RegisterID* emitCatch(RegisterID*, Label* start, Label* end); - void emitThrow(RegisterID* exc) { emitUnaryNoDstOp(op_throw, exc); } + void emitThrow(RegisterID* exc) + { + m_usesExceptions = true; + emitUnaryNoDstOp(op_throw, exc); + } + RegisterID* emitNewError(RegisterID* dst, bool isReferenceError, JSValue message); void emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value); @@ -552,6 +557,7 @@ namespace JSC { unsigned m_emitNodeDepth; + bool m_usesExceptions; bool m_regeneratingForExceptionInfo; CodeBlock* m_codeBlockBeingRegeneratedFrom; diff --git a/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/JavaScriptCore/bytecompiler/NodesCodegen.cpp index 765230e..cdf3e49 100644 --- a/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -39,6 +39,7 @@ #include "Operations.h" #include "Parser.h" #include "PropertyNameArray.h" +#include "RegExpCache.h" #include "RegExpObject.h" #include "SamplingTool.h" #include <wtf/Assertions.h> @@ -144,7 +145,7 @@ RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr<RegExp> regExp = RegExp::create(generator.globalData(), m_pattern.ustring(), m_flags.ustring()); + RefPtr<RegExp> regExp = generator.globalData()->regExpCache()->lookupOrCreate(m_pattern.ustring(), m_flags.ustring()); if (!regExp->isValid()) return emitThrowError(generator, false, "Invalid regular expression: %s", regExp->errorMessage()); if (dst == generator.ignoredResult()) diff --git a/JavaScriptCore/create_jit_stubs b/JavaScriptCore/create_jit_stubs index 4d510ea..9bb9ee5 100644 --- a/JavaScriptCore/create_jit_stubs +++ b/JavaScriptCore/create_jit_stubs @@ -42,6 +42,7 @@ $file = $ARGV[0]; die "$usage\n" unless ($prefix and $file); my $stub_template = ""; +my $output_end = ""; my $stub = ""; my $rtype = ""; @@ -51,9 +52,17 @@ print STDERR "Creating JIT stubs for $file \n"; open(IN, $file) or die "No such file $file"; while ( $_ = <IN> ) { + if ( /^$prefix\_BEGIN\((.*)\)/ ) { + $stub = $1; + $stub =~ s/$offset_template/$offset/g; + print $stub . "\n"; + } if ( /^$prefix\((.*)\)/ ) { $stub_template .= $1 . "\n"; } + if ( /^$prefix\_END\((.*)\)/ ) { + $output_end .= $1 . "\n"; + } if ( /^DEFINE_STUB_FUNCTION\((.*), (.*)\)/ ) { $stub = $stub_template; $rtype = quotemeta($1); @@ -66,4 +75,6 @@ while ( $_ = <IN> ) { } } +print $output_end; + close(IN); diff --git a/JavaScriptCore/interpreter/CallFrame.cpp b/JavaScriptCore/interpreter/CallFrame.cpp index f53e6f4..ff061db 100644 --- a/JavaScriptCore/interpreter/CallFrame.cpp +++ b/JavaScriptCore/interpreter/CallFrame.cpp @@ -42,6 +42,12 @@ void CallFrame::dumpCaller() interpreter()->retrieveLastCaller(this, signedLineNumber, sourceID, urlString, function); printf("Callpoint => %s:%d\n", urlString.ascii(), signedLineNumber); } + +RegisterFile* CallFrame::registerFile() +{ + return &interpreter()->registerFile(); +} + #endif } diff --git a/JavaScriptCore/interpreter/CallFrame.h b/JavaScriptCore/interpreter/CallFrame.h index 723d4ae..7ea59fb 100644 --- a/JavaScriptCore/interpreter/CallFrame.h +++ b/JavaScriptCore/interpreter/CallFrame.h @@ -117,6 +117,7 @@ namespace JSC { CallFrame* callerFrame, int argc, JSObject* callee) { ASSERT(callerFrame); // Use noCaller() rather than 0 for the outer host call frame caller. + ASSERT(callerFrame == noCaller() || callerFrame->removeHostCallFrameFlag()->registerFile()->end() >= this); setCodeBlock(codeBlock); setScopeChain(scopeChain); @@ -155,7 +156,9 @@ namespace JSC { private: static const intptr_t HostCallFrameFlag = 1; - +#ifndef NDEBUG + RegisterFile* registerFile(); +#endif ExecState(); ~ExecState(); }; diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp index 91f5c0a..7c5bc6f 100644 --- a/JavaScriptCore/interpreter/Interpreter.cpp +++ b/JavaScriptCore/interpreter/Interpreter.cpp @@ -456,7 +456,6 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) printf("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it; printf("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it; printf("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it; - ++it; printf("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it; printf("[Callee] | %10p | %p \n", it, (*it).function()); ++it; printf("-----------------------------------------------------------------------------\n"); @@ -643,6 +642,10 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, S } CodeBlock* codeBlock = &program->bytecode(callFrame, scopeChain); + if (!codeBlock) { + *exception = createStackOverflowError(callFrame); + return jsNull(); + } Register* oldEnd = m_registerFile.end(); Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters; @@ -722,9 +725,12 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT if (callType == CallTypeJS) { ScopeChainNode* callDataScopeChain = callData.js.scopeChain; - CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecodeForCall(callFrame, callDataScopeChain); + CodeBlock* newCodeBlock = callData.js.functionExecutable->bytecodeForCall(callFrame, callDataScopeChain); - newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount); + if (newCodeBlock) + newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount); + else + newCallFrame = 0; if (UNLIKELY(!newCallFrame)) { *exception = createStackOverflowError(callFrame); m_registerFile.shrink(oldEnd); @@ -811,9 +817,12 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc if (constructType == ConstructTypeJS) { ScopeChainNode* constructDataScopeChain = constructData.js.scopeChain; - CodeBlock* newCodeBlock = &constructData.js.functionExecutable->bytecodeForConstruct(callFrame, constructDataScopeChain); + CodeBlock* newCodeBlock = constructData.js.functionExecutable->bytecodeForConstruct(callFrame, constructDataScopeChain); + if (newCodeBlock) + newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount); + else + newCallFrame = 0; - newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount); if (UNLIKELY(!newCallFrame)) { *exception = createStackOverflowError(callFrame); m_registerFile.shrink(oldEnd); @@ -902,8 +911,11 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionE for (int i = 0; i < argc; ++i) newCallFrame->r(++dst) = jsUndefined(); - CodeBlock* codeBlock = &FunctionExecutable->bytecodeForCall(callFrame, scopeChain); - newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc); + CodeBlock* codeBlock = FunctionExecutable->bytecodeForCall(callFrame, scopeChain); + if (codeBlock) + newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc); + else + newCallFrame = 0; if (UNLIKELY(!newCallFrame)) { *exception = createStackOverflowError(callFrame); m_registerFile.shrink(oldEnd); @@ -968,6 +980,10 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject); EvalCodeBlock* codeBlock = &eval->bytecode(callFrame, scopeChain); + if (!codeBlock) { + *exception = createStackOverflowError(callFrame); + return jsNull(); + } JSVariableObject* variableObject; for (ScopeChainNode* node = scopeChain; ; node = node->next) { @@ -3619,11 +3635,13 @@ skip_id_custom_self: if (callType == CallTypeJS) { ScopeChainNode* callDataScopeChain = callData.js.scopeChain; - CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecodeForCall(callFrame, callDataScopeChain); + CodeBlock* newCodeBlock = callData.js.functionExecutable->bytecodeForCall(callFrame, callDataScopeChain); CallFrame* previousCallFrame = callFrame; - - callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount); + if (newCodeBlock) + callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount); + else + callFrame = 0; if (UNLIKELY(!callFrame)) { callFrame = previousCallFrame; exceptionValue = createStackOverflowError(callFrame); @@ -3645,6 +3663,11 @@ skip_id_custom_self: if (callType == CallTypeHost) { ScopeChainNode* scopeChain = callFrame->scopeChain(); CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); + if (!registerFile->grow(newCallFrame->registers())) { + exceptionValue = createStackOverflowError(callFrame); + goto vm_throw; + } + newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call), scopeChain, callFrame, argCount, asObject(v)); JSValue returnValue; @@ -3766,11 +3789,13 @@ skip_id_custom_self: if (callType == CallTypeJS) { ScopeChainNode* callDataScopeChain = callData.js.scopeChain; - CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecodeForCall(callFrame, callDataScopeChain); + CodeBlock* newCodeBlock = callData.js.functionExecutable->bytecodeForCall(callFrame, callDataScopeChain); CallFrame* previousCallFrame = callFrame; - - callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount); + if (newCodeBlock) + callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount); + else + callFrame = 0; if (UNLIKELY(!callFrame)) { callFrame = previousCallFrame; exceptionValue = createStackOverflowError(callFrame); @@ -3792,6 +3817,10 @@ skip_id_custom_self: if (callType == CallTypeHost) { ScopeChainNode* scopeChain = callFrame->scopeChain(); CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); + if (!registerFile->grow(newCallFrame->registers())) { + exceptionValue = createStackOverflowError(callFrame); + goto vm_throw; + } newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_varargs), scopeChain, callFrame, argCount, asObject(v)); JSValue returnValue; @@ -4085,11 +4114,15 @@ skip_id_custom_self: if (constructType == ConstructTypeJS) { ScopeChainNode* callDataScopeChain = constructData.js.scopeChain; - CodeBlock* newCodeBlock = &constructData.js.functionExecutable->bytecodeForConstruct(callFrame, callDataScopeChain); + CodeBlock* newCodeBlock = constructData.js.functionExecutable->bytecodeForConstruct(callFrame, callDataScopeChain); CallFrame* previousCallFrame = callFrame; - callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount); + if (newCodeBlock) + callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount); + else + callFrame = 0; + if (UNLIKELY(!callFrame)) { callFrame = previousCallFrame; exceptionValue = createStackOverflowError(callFrame); @@ -4110,6 +4143,10 @@ skip_id_custom_self: if (constructType == ConstructTypeHost) { ScopeChainNode* scopeChain = callFrame->scopeChain(); CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); + if (!registerFile->grow(newCallFrame->registers())) { + exceptionValue = createStackOverflowError(callFrame); + goto vm_throw; + } newCallFrame->init(0, vPC + OPCODE_LENGTH(op_construct), scopeChain, callFrame, argCount, asObject(v)); JSValue returnValue; diff --git a/JavaScriptCore/jit/ExecutableAllocator.h b/JavaScriptCore/jit/ExecutableAllocator.h index 610b788..703f63f 100644 --- a/JavaScriptCore/jit/ExecutableAllocator.h +++ b/JavaScriptCore/jit/ExecutableAllocator.h @@ -25,7 +25,6 @@ #ifndef ExecutableAllocator_h #define ExecutableAllocator_h - #include <stddef.h> // for ptrdiff_t #include <limits> #include <wtf/Assertions.h> @@ -80,7 +79,7 @@ inline size_t roundUpAllocationSize(size_t request, size_t granularity) } -#if ENABLE(ASSEMBLER) +#if ENABLE(JIT) && ENABLE(ASSEMBLER) namespace JSC { @@ -316,6 +315,6 @@ inline void* ExecutablePool::poolAllocate(size_t n) } -#endif // ENABLE(ASSEMBLER) +#endif // ENABLE(JIT) && ENABLE(ASSEMBLER) #endif // !defined(ExecutableAllocator) diff --git a/JavaScriptCore/jit/JITInlineMethods.h b/JavaScriptCore/jit/JITInlineMethods.h index cba290b..04f7158 100644 --- a/JavaScriptCore/jit/JITInlineMethods.h +++ b/JavaScriptCore/jit/JITInlineMethods.h @@ -645,7 +645,7 @@ ALWAYS_INLINE bool JIT::isOperandConstantImmediateInt(unsigned src) ALWAYS_INLINE void JIT::emitPutVirtualRegister(unsigned dst, RegisterID from) { storePtr(from, Address(callFrameRegister, dst * sizeof(Register))); - m_lastResultBytecodeRegister = (from == cachedResultRegister) ? dst : std::numeric_limits<int>::max(); + m_lastResultBytecodeRegister = (from == cachedResultRegister) ? static_cast<int>(dst) : std::numeric_limits<int>::max(); } ALWAYS_INLINE void JIT::emitInitRegister(unsigned dst) diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp index 0848348..9a34931 100644 --- a/JavaScriptCore/jit/JITOpcodes.cpp +++ b/JavaScriptCore/jit/JITOpcodes.cpp @@ -73,12 +73,14 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable // VirtualCallLink Trampoline // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. + JumpList callLazyLinkFailures; Label virtualCallLinkBegin = align(); compileOpCallInitializeCallFrame(); preserveReturnAddressAfterCall(regT3); emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); restoreArgumentReference(); Call callLazyLinkCall = call(); + callLazyLinkFailures.append(branchTestPtr(Zero, regT0)); restoreReturnAddressBeforeReturn(regT3); emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1); jump(regT0); @@ -91,10 +93,24 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); restoreArgumentReference(); Call callLazyLinkConstruct = call(); + callLazyLinkFailures.append(branchTestPtr(Zero, regT0)); restoreReturnAddressBeforeReturn(regT3); emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1); jump(regT0); + // If the parser fails we want to be able to be able to keep going, + // So we handle this as a parse failure. + callLazyLinkFailures.link(this); + emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); + restoreReturnAddressBeforeReturn(regT1); + move(ImmPtr(&globalData->exceptionLocation), regT2); + storePtr(regT1, regT2); + poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); + poke(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value())); + ret(); + + // VirtualCall Trampoline // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. Label virtualCallBegin = align(); @@ -181,6 +197,7 @@ JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isCon Label nativeCallThunk = align(); +#if CPU(X86_64) // Load caller frame's scope chain into this callframe so that whatever we call can // get to its global data. emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0); @@ -190,7 +207,6 @@ JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isCon peek(regT1); emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC); -#if CPU(X86_64) // Calling convention: f(edi, esi, edx, ecx, ...); // Host function signature: f(ExecState*); move(callFrameRegister, X86Registers::edi); @@ -204,6 +220,27 @@ JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isCon addPtr(Imm32(16 - sizeof(void*)), stackPointerRegister); +#elif CPU(ARM) + // Load caller frame's scope chain into this callframe so that whatever we call can + // get to its global data. + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2); + emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2); + emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); + + preserveReturnAddressAfterCall(regT3); // Callee preserved + emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); + + // Calling convention: f(r0 == regT0, r1 == regT1, ...); + // Host function signature: f(ExecState*); + move(callFrameRegister, ARMRegisters::r0); + + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, ARMRegisters::r1); + move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. + loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + call(Address(regT2, executableOffsetToFunction)); + + restoreReturnAddressBeforeReturn(regT3); + #elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL) #error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform." #else @@ -220,12 +257,18 @@ JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isCon // Handle an exception exceptionHandler.link(this); + // Grab the return address. - peek(regT1); + preserveReturnAddressAfterCall(regT1); + move(ImmPtr(&globalData->exceptionLocation), regT2); storePtr(regT1, regT2); - poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); - poke(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value())); + poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); + + // Set the return address. + move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1); + restoreReturnAddressBeforeReturn(regT1); + ret(); return nativeCallThunk; diff --git a/JavaScriptCore/jit/JITOpcodes32_64.cpp b/JavaScriptCore/jit/JITOpcodes32_64.cpp index 239751f..a44a8a1 100644 --- a/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -66,8 +66,8 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable #endif // (2) Trampolines for the slow cases of op_call / op_call_eval / op_construct. - #if ENABLE(JIT_OPTIMIZE_CALL) + JumpList callLazyLinkFailures; // VirtualCallLink Trampoline // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. Label virtualCallLinkBegin = align(); @@ -76,6 +76,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); restoreArgumentReference(); Call callLazyLinkCall = call(); + callLazyLinkFailures.append(branchTestPtr(Zero, regT0)); restoreReturnAddressBeforeReturn(regT3); emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1); jump(regT0); @@ -89,8 +90,22 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable restoreArgumentReference(); Call callLazyLinkConstruct = call(); restoreReturnAddressBeforeReturn(regT3); + callLazyLinkFailures.append(branchTestPtr(Zero, regT0)); emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1); jump(regT0); + + // If the parser fails we want to be able to be able to keep going, + // So we handle this as a parse failure. + callLazyLinkFailures.link(this); + emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); + restoreReturnAddressBeforeReturn(regT1); + move(ImmPtr(&globalData->exceptionLocation), regT2); + storePtr(regT1, regT2); + poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); + poke(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value())); + ret(); + #endif // ENABLE(JIT_OPTIMIZE_CALL) // VirtualCall Trampoline @@ -181,6 +196,7 @@ JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isCon Label nativeCallThunk = align(); +#if CPU(X86) // Load caller frame's scope chain into this callframe so that whatever we call can // get to its global data. emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0); @@ -190,7 +206,6 @@ JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isCon peek(regT1); emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC); -#if CPU(X86) // Calling convention: f(ecx, edx, ...); // Host function signature: f(ExecState*); move(callFrameRegister, X86Registers::ecx); @@ -205,6 +220,28 @@ JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isCon addPtr(Imm32(16 - sizeof(void*)), stackPointerRegister); +#elif CPU(ARM) + // Load caller frame's scope chain into this callframe so that whatever we call can + // get to its global data. + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2); + emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2); + emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); + + preserveReturnAddressAfterCall(regT3); // Callee preserved + emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); + + // Calling convention: f(r0 == regT0, r1 == regT1, ...); + // Host function signature: f(ExecState*); + move(callFrameRegister, ARMRegisters::r0); + + // call the function + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, ARMRegisters::r1); + move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. + loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + call(Address(regT2, executableOffsetToFunction)); + + restoreReturnAddressBeforeReturn(regT3); + #elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL) #error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform." #else @@ -220,11 +257,18 @@ JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isCon // Handle an exception sawException.link(this); - peek(regT1); + + // Grab the return address. + preserveReturnAddressAfterCall(regT1); + move(ImmPtr(&globalData->exceptionLocation), regT2); storePtr(regT1, regT2); - poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); - poke(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value())); + poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); + + // Set the return address. + move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1); + restoreReturnAddressBeforeReturn(regT1); + ret(); return nativeCallThunk; @@ -258,6 +302,29 @@ JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executa addPtr(Imm32(16 - sizeof(void*)), stackPointerRegister); +#elif CPU(ARM) + // Load caller frame's scope chain into this callframe so that whatever we call can + // get to its global data. + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2); + emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2); + emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); + + preserveReturnAddressAfterCall(regT3); // Callee preserved + emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); + + // Calling convention: f(r0 == regT0, r1 == regT1, ...); + // Host function signature: f(ExecState*); + move(callFrameRegister, ARMRegisters::r0); + + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, ARMRegisters::r1); + move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. + loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + + // call the function + nativeCall = call(); + + restoreReturnAddressBeforeReturn(regT3); + #elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL) #error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform." #else @@ -272,11 +339,18 @@ JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executa // Handle an exception sawException.link(this); - peek(regT1); + + // Grab the return address. + preserveReturnAddressAfterCall(regT1); + move(ImmPtr(&globalData->exceptionLocation), regT2); storePtr(regT1, regT2); - poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); - poke(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value())); + poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); + + // Set the return address. + move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1); + restoreReturnAddressBeforeReturn(regT1); + ret(); // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. @@ -607,8 +681,8 @@ void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool dynamic) // Load property. loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_externalStorage)), regT2); load32(offsetAddr, regT3); - load32(BaseIndex(regT2, regT3, TimesEight), regT0); // payload - load32(BaseIndex(regT2, regT3, TimesEight, 4), regT1); // tag + load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload + load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag emitStore(dst, regT1, regT0); map(m_bytecodeOffset + dynamic ? OPCODE_LENGTH(op_resolve_global_dynamic) : OPCODE_LENGTH(op_resolve_global), dst, regT1, regT0); } diff --git a/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/JavaScriptCore/jit/JITPropertyAccess32_64.cpp index 6b8af7c..16cf84a 100644 --- a/JavaScriptCore/jit/JITPropertyAccess32_64.cpp +++ b/JavaScriptCore/jit/JITPropertyAccess32_64.cpp @@ -314,8 +314,8 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3); addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength)))); - load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), regT1); // tag - load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); // payload + load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag + load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload addSlowCase(branch32(Equal, regT1, Imm32(JSValue::EmptyValueTag))); emitStore(dst, regT1, regT0); @@ -366,12 +366,12 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3); - Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), Imm32(JSValue::EmptyValueTag)); + Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::EmptyValueTag)); Label storeResult(this); emitLoad(value, regT1, regT0); - store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); // payload - store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4)); // tag + store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); // payload + store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); // tag Jump end = jump(); empty.link(this); @@ -571,8 +571,8 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, Register void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset) { if (base->isUsingInlineStorage()) { - load32(reinterpret_cast<char*>(&base->m_inlineStorage[cachedOffset]), resultPayload); - load32(reinterpret_cast<char*>(&base->m_inlineStorage[cachedOffset]) + 4, resultTag); + load32(reinterpret_cast<char*>(&base->m_inlineStorage[cachedOffset]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload), resultPayload); + load32(reinterpret_cast<char*>(&base->m_inlineStorage[cachedOffset]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag), resultTag); return; } @@ -580,8 +580,8 @@ void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID res PropertyStorage* protoPropertyStorage = &base->m_externalStorage; loadPtr(static_cast<void*>(protoPropertyStorage), temp); - load32(Address(temp, offset), resultPayload); - load32(Address(temp, offset + 4), resultTag); + load32(Address(temp, offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload); + load32(Address(temp, offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag); } void JIT::testPrototype(Structure* structure, JumpList& failureCases) @@ -628,8 +628,8 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure add32(Imm32(1), AbsoluteAddress(newStructure->addressOfCount())); storePtr(ImmPtr(newStructure), Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure))); - load32(Address(stackPointerRegister, offsetof(struct JITStackFrame, args[2]) + sizeof(void*)), regT3); - load32(Address(stackPointerRegister, offsetof(struct JITStackFrame, args[2]) + sizeof(void*) + 4), regT2); + load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + sizeof(void*) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT3); + load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + sizeof(void*) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT2); // Write the value compilePutDirectOffset(regT0, regT2, regT3, newStructure, cachedOffset); @@ -673,8 +673,8 @@ void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, St // Patch the offset into the propoerty map to load from, then patch the Structure to look for. repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetGetByIdStructure), structure); - repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset1), offset); // payload - repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset2), offset + 4); // tag + repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset1), offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); // payload + repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset2), offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag } void JIT::patchMethodCallProto(CodeBlock* codeBlock, MethodCallLinkInfo& methodCallLinkInfo, JSFunction* callee, Structure* structure, JSObject* proto, ReturnAddressPtr returnAddress) @@ -714,8 +714,8 @@ void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, // Patch the offset into the propoerty map to load from, then patch the Structure to look for. repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetPutByIdStructure), structure); - repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset1), offset); // payload - repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset2), offset + 4); // tag + repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset1), offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); // payload + repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset2), offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag } void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) @@ -1122,8 +1122,8 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, Register ASSERT(sizeof(JSValue) == 8); Jump notUsingInlineStorage = branch32(NotEqual, Address(structure, OBJECT_OFFSETOF(Structure, m_propertyStorageCapacity)), Imm32(JSObject::inlineStorageCapacity)); - loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSObject, m_inlineStorage)+OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload); - loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSObject, m_inlineStorage)+OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag); + loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSObject, m_inlineStorage) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload); + loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSObject, m_inlineStorage) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag); Jump finishedLoad = jump(); notUsingInlineStorage.link(this); loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_externalStorage)), base); diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp index ff0dc3f..c4a6507 100644 --- a/JavaScriptCore/jit/JITStubs.cpp +++ b/JavaScriptCore/jit/JITStubs.cpp @@ -1967,7 +1967,11 @@ DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall) codePtr = executable->generatedJITCodeForCall().addressForCall(); else { FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); - codeBlock = &functionExecutable->bytecodeForCall(stackFrame.callFrame, callee->scope().node()); + codeBlock = functionExecutable->bytecodeForCall(stackFrame.callFrame, callee->scope().node()); + if (!codeBlock) { + stackFrame.callFrame->globalData().exception = createStackOverflowError(callFrame); + return 0; + } functionExecutable->jitCodeForCall(callFrame, callee->scope().node()); if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters)) codePtr = functionExecutable->generatedJITCodeForCall().addressForCall(); @@ -1997,7 +2001,11 @@ DEFINE_STUB_FUNCTION(void*, vm_lazyLinkConstruct) codePtr = executable->generatedJITCodeForConstruct().addressForCall(); else { FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); - codeBlock = &functionExecutable->bytecodeForConstruct(stackFrame.callFrame, callee->scope().node()); + codeBlock = functionExecutable->bytecodeForConstruct(stackFrame.callFrame, callee->scope().node()); + if (!codeBlock) { + throwStackOverflowError(callFrame, stackFrame.globalData, ReturnAddressPtr(callFrame->returnPC()), STUB_RETURN_ADDRESS); + VM_THROW_EXCEPTION(); + } functionExecutable->jitCodeForConstruct(callFrame, callee->scope().node()); if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters)) codePtr = functionExecutable->generatedJITCodeForConstruct().addressForCall(); @@ -2040,7 +2048,10 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction) int argCount = stackFrame.args[2].int32(); CallFrame* previousCallFrame = stackFrame.callFrame; CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset); - + if (!stackFrame.registerFile->grow(callFrame->registers())) { + throwStackOverflowError(previousCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS); + VM_THROW_EXCEPTION(); + } callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(funcVal)); stackFrame.callFrame = callFrame; @@ -2175,6 +2186,10 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct) int argCount = stackFrame.args[2].int32(); CallFrame* previousCallFrame = stackFrame.callFrame; CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset); + if (!stackFrame.registerFile->grow(callFrame->registers())) { + throwStackOverflowError(previousCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS); + VM_THROW_EXCEPTION(); + } callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(constrVal)); stackFrame.callFrame = callFrame; diff --git a/JavaScriptCore/jsc/CMakeLists.txt b/JavaScriptCore/jsc/CMakeLists.txt index cc39e14..970c20f 100644 --- a/JavaScriptCore/jsc/CMakeLists.txt +++ b/JavaScriptCore/jsc/CMakeLists.txt @@ -9,11 +9,8 @@ SET(JSC_LIBRARIES ${JavaScriptCore_LIBRARY_NAME} ) - -SET(JSC_PORT_FLAGS ) INCLUDE_IF_EXISTS(${JAVASCRIPTCORE_DIR}/jsc/CMakeLists${PORT}.txt) - WEBKIT_WRAP_SOURCELIST(${JSC_SOURCES}) INCLUDE_DIRECTORIES(./ ${JavaScriptCore_INCLUDE_DIRECTORIES}) ADD_EXECUTABLE(${JSC_EXECUTABLE_NAME} ${JSC_HEADERS} ${JSC_SOURCES}) diff --git a/JavaScriptCore/parser/ASTBuilder.h b/JavaScriptCore/parser/ASTBuilder.h new file mode 100644 index 0000000..7dcdff0 --- /dev/null +++ b/JavaScriptCore/parser/ASTBuilder.h @@ -0,0 +1,925 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ASTBuilder_h +#define ASTBuilder_h + +#include "NodeConstructors.h" +#include "SyntaxChecker.h" +#include <utility> + +namespace JSC { + +class ASTBuilder { + struct BinaryOpInfo { + BinaryOpInfo() {} + BinaryOpInfo(int s, int d, int e, bool r) + : start(s) + , divot(d) + , end(e) + , hasAssignment(r) + { + } + BinaryOpInfo(const BinaryOpInfo& lhs, const BinaryOpInfo& rhs) + : start(lhs.start) + , divot(rhs.start) + , end(rhs.end) + , hasAssignment(lhs.hasAssignment || rhs.hasAssignment) + { + } + int start; + int divot; + int end; + bool hasAssignment; + }; + + + struct AssignmentInfo { + AssignmentInfo() {} + AssignmentInfo(ExpressionNode* node, int start, int divot, int initAssignments, Operator op) + : m_node(node) + , m_start(start) + , m_divot(divot) + , m_initAssignments(initAssignments) + , m_op(op) + { + } + ExpressionNode* m_node; + int m_start; + int m_divot; + int m_initAssignments; + Operator m_op; + }; +public: + ASTBuilder(JSGlobalData* globalData, Lexer* lexer) + : m_globalData(globalData) + , m_lexer(lexer) + , m_evalCount(0) + { + m_scopes.append(Scope(globalData)); + } + + typedef SyntaxChecker FunctionBodyBuilder; + + typedef ExpressionNode* Expression; + typedef JSC::SourceElements* SourceElements; + typedef ArgumentsNode* Arguments; + typedef CommaNode* Comma; + typedef PropertyNode* Property; + typedef PropertyListNode* PropertyList; + typedef ElementNode* ElementList; + typedef ArgumentListNode* ArgumentsList; + typedef ParameterNode* FormalParameterList; + typedef FunctionBodyNode* FunctionBody; + typedef StatementNode* Statement; + typedef ClauseListNode* ClauseList; + typedef CaseClauseNode* Clause; + typedef ConstDeclNode* ConstDeclList; + typedef std::pair<ExpressionNode*, BinaryOpInfo> BinaryOperand; + + static const bool CreatesAST = true; + + ExpressionNode* makeBinaryNode(int token, std::pair<ExpressionNode*, BinaryOpInfo>, std::pair<ExpressionNode*, BinaryOpInfo>); + ExpressionNode* makeFunctionCallNode(ExpressionNode* func, ArgumentsNode* args, int start, int divot, int end); + + JSC::SourceElements* createSourceElements() { return new (m_globalData) JSC::SourceElements(m_globalData); } + + ParserArenaData<DeclarationStacks::VarStack>* varDeclarations() { return m_scopes.last().m_varDeclarations; } + ParserArenaData<DeclarationStacks::FunctionStack>* funcDeclarations() { return m_scopes.last().m_funcDeclarations; } + int features() const { return m_scopes.last().m_features; } + int numConstants() const { return m_scopes.last().m_numConstants; } + + void appendToComma(CommaNode* commaNode, ExpressionNode* expr) { commaNode->append(expr); } + + CommaNode* createCommaExpr(ExpressionNode* lhs, ExpressionNode* rhs) { return new (m_globalData) CommaNode(m_globalData, lhs, rhs); } + + ExpressionNode* makeAssignNode(ExpressionNode* left, Operator, ExpressionNode* right, bool leftHasAssignments, bool rightHasAssignments, int start, int divot, int end); + ExpressionNode* makePrefixNode(ExpressionNode*, Operator, int start, int divot, int end); + ExpressionNode* makePostfixNode(ExpressionNode*, Operator, int start, int divot, int end); + ExpressionNode* makeTypeOfNode(ExpressionNode*); + ExpressionNode* makeDeleteNode(ExpressionNode*, int start, int divot, int end); + ExpressionNode* makeNegateNode(ExpressionNode*); + ExpressionNode* makeBitwiseNotNode(ExpressionNode*); + ExpressionNode* makeMultNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); + ExpressionNode* makeDivNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); + ExpressionNode* makeAddNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); + ExpressionNode* makeSubNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); + ExpressionNode* makeLeftShiftNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); + ExpressionNode* makeRightShiftNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); + + ExpressionNode* createLogicalNot(ExpressionNode* expr) { return new (m_globalData) LogicalNotNode(m_globalData, expr); } + ExpressionNode* createUnaryPlus(ExpressionNode* expr) { return new (m_globalData) UnaryPlusNode(m_globalData, expr); } + ExpressionNode* createVoid(ExpressionNode* expr) + { + incConstants(); + return new (m_globalData) VoidNode(m_globalData, expr); + } + ExpressionNode* thisExpr() + { + usesThis(); + return new (m_globalData) ThisNode(m_globalData); + } + ExpressionNode* createResolve(const Identifier* ident, int start) + { + if (m_globalData->propertyNames->arguments == *ident) + usesArguments(); + return new (m_globalData) ResolveNode(m_globalData, *ident, start); + } + ExpressionNode* createObjectLiteral() { return new (m_globalData) ObjectLiteralNode(m_globalData); } + ExpressionNode* createObjectLiteral(PropertyListNode* properties) { return new (m_globalData) ObjectLiteralNode(m_globalData, properties); } + + ExpressionNode* createArray(int elisions) + { + if (elisions) + incConstants(); + return new (m_globalData) ArrayNode(m_globalData, elisions); + } + + ExpressionNode* createArray(ElementNode* elems) { return new (m_globalData) ArrayNode(m_globalData, elems); } + ExpressionNode* createArray(int elisions, ElementNode* elems) + { + if (elisions) + incConstants(); + return new (m_globalData) ArrayNode(m_globalData, elisions, elems); + } + ExpressionNode* createNumberExpr(double d) + { + incConstants(); + return new (m_globalData) NumberNode(m_globalData, d); + } + + ExpressionNode* createString(const Identifier* string) + { + incConstants(); + return new (m_globalData) StringNode(m_globalData, *string); + } + + ExpressionNode* createBoolean(bool b) + { + incConstants(); + return new (m_globalData) BooleanNode(m_globalData, b); + } + + ExpressionNode* createNull() + { + incConstants(); + return new (m_globalData) NullNode(m_globalData); + } + + ExpressionNode* createBracketAccess(ExpressionNode* base, ExpressionNode* property, bool propertyHasAssignments, int start, int divot, int end) + { + BracketAccessorNode* node = new (m_globalData) BracketAccessorNode(m_globalData, base, property, propertyHasAssignments); + setExceptionLocation(node, start, divot, end); + return node; + } + + ExpressionNode* createDotAccess(ExpressionNode* base, const Identifier& property, int start, int divot, int end) + { + DotAccessorNode* node = new (m_globalData) DotAccessorNode(m_globalData, base, property); + setExceptionLocation(node, start, divot, end); + return node; + } + + ExpressionNode* createRegex(const Identifier& pattern, const Identifier& flags, int start) + { + RegExpNode* node = new (m_globalData) RegExpNode(m_globalData, pattern, flags); + int size = pattern.size() + 2; // + 2 for the two /'s + setExceptionLocation(node, start, start + size, start + size); + return node; + } + + ExpressionNode* createNewExpr(ExpressionNode* expr, ArgumentsNode* arguments, int start, int divot, int end) + { + NewExprNode* node = new (m_globalData) NewExprNode(m_globalData, expr, arguments); + setExceptionLocation(node, start, divot, end); + return node; + } + + ExpressionNode* createNewExpr(ExpressionNode* expr, int start, int end) + { + NewExprNode* node = new (m_globalData) NewExprNode(m_globalData, expr); + setExceptionLocation(node, start, end, end); + return node; + } + + ExpressionNode* createConditionalExpr(ExpressionNode* condition, ExpressionNode* lhs, ExpressionNode* rhs) + { + return new (m_globalData) ConditionalNode(m_globalData, condition, lhs, rhs); + } + + ExpressionNode* createAssignResolve(const Identifier& ident, ExpressionNode* rhs, bool rhsHasAssignment, int start, int divot, int end) + { + AssignResolveNode* node = new (m_globalData) AssignResolveNode(m_globalData, ident, rhs, rhsHasAssignment); + setExceptionLocation(node, start, divot, end); + return node; + } + + ExpressionNode* createFunctionExpr(const Identifier* name, FunctionBodyNode* body, ParameterNode* parameters, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine) + { + FuncExprNode* result = new (m_globalData) FuncExprNode(m_globalData, *name, body, m_lexer->sourceCode(openBracePos, closeBracePos, bodyStartLine), parameters); + body->setLoc(bodyStartLine, bodyEndLine); + return result; + } + + FunctionBodyNode* createFunctionBody() + { + usesClosures(); + return FunctionBodyNode::create(m_globalData); + } + + PropertyNode* createGetterOrSetterProperty(const Identifier* getOrSet, const Identifier* name, ParameterNode* params, FunctionBodyNode* body, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine) + { + ASSERT(name); + PropertyNode::Type type; + if (*getOrSet == "get") + type = PropertyNode::Getter; + else if (*getOrSet == "set") + type = PropertyNode::Setter; + else + return 0; + body->setLoc(bodyStartLine, bodyEndLine); + return new (m_globalData) PropertyNode(m_globalData, *name, new (m_globalData) FuncExprNode(m_globalData, m_globalData->propertyNames->nullIdentifier, body, m_lexer->sourceCode(openBracePos, closeBracePos, bodyStartLine), params), type); + } + + + ArgumentsNode* createArguments() { return new (m_globalData) ArgumentsNode(m_globalData); } + ArgumentsNode* createArguments(ArgumentListNode* args) { return new (m_globalData) ArgumentsNode(m_globalData, args); } + ArgumentListNode* createArgumentsList(ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(m_globalData, arg); } + ArgumentListNode* createArgumentsList(ArgumentListNode* args, ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(m_globalData, args, arg); } + + PropertyNode* createProperty(const Identifier* propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, *propertyName, node, type); } + PropertyNode* createProperty(double propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, propertyName, node, type); } + PropertyListNode* createPropertyList(PropertyNode* property) { return new (m_globalData) PropertyListNode(m_globalData, property); } + PropertyListNode* createPropertyList(PropertyNode* property, PropertyListNode* tail) { return new (m_globalData) PropertyListNode(m_globalData, property, tail); } + + ElementNode* createElementList(int elisions, ExpressionNode* expr) { return new (m_globalData) ElementNode(m_globalData, elisions, expr); } + ElementNode* createElementList(ElementNode* elems, int elisions, ExpressionNode* expr) { return new (m_globalData) ElementNode(m_globalData, elems, elisions, expr); } + + ParameterNode* createFormalParameterList(const Identifier& ident) { return new (m_globalData) ParameterNode(m_globalData, ident); } + ParameterNode* createFormalParameterList(ParameterNode* list, const Identifier& ident) { return new (m_globalData) ParameterNode(m_globalData, list, ident); } + + CaseClauseNode* createClause(ExpressionNode* expr, JSC::SourceElements* statements) { return new (m_globalData) CaseClauseNode(m_globalData, expr, statements); } + ClauseListNode* createClauseList(CaseClauseNode* clause) { return new (m_globalData) ClauseListNode(m_globalData, clause); } + ClauseListNode* createClauseList(ClauseListNode* tail, CaseClauseNode* clause) { return new (m_globalData) ClauseListNode(m_globalData, tail, clause); } + + void setUsesArguments(FunctionBodyNode* node) { node->setUsesArguments(); } + + StatementNode* createFuncDeclStatement(const Identifier* name, FunctionBodyNode* body, ParameterNode* parameters, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine) + { + FuncDeclNode* decl = new (m_globalData) FuncDeclNode(m_globalData, *name, body, m_lexer->sourceCode(openBracePos, closeBracePos, bodyStartLine), parameters); + if (*name == m_globalData->propertyNames->arguments) + usesArguments(); + m_scopes.last().m_funcDeclarations->data.append(decl->body()); + body->setLoc(bodyStartLine, bodyEndLine); + return decl; + } + + StatementNode* createBlockStatement(JSC::SourceElements* elements, int startLine, int endLine) + { + BlockNode* block = new (m_globalData) BlockNode(m_globalData, elements); + block->setLoc(startLine, endLine); + return block; + } + + StatementNode* createExprStatement(ExpressionNode* expr, int start, int end) + { + ExprStatementNode* result = new (m_globalData) ExprStatementNode(m_globalData, expr); + result->setLoc(start, end); + return result; + } + + StatementNode* createIfStatement(ExpressionNode* condition, StatementNode* trueBlock, int start, int end) + { + IfNode* result = new (m_globalData) IfNode(m_globalData, condition, trueBlock); + result->setLoc(start, end); + return result; + } + + StatementNode* createIfStatement(ExpressionNode* condition, StatementNode* trueBlock, StatementNode* falseBlock, int start, int end) + { + IfNode* result = new (m_globalData) IfElseNode(m_globalData, condition, trueBlock, falseBlock); + result->setLoc(start, end); + return result; + } + + StatementNode* createForLoop(ExpressionNode* initializer, ExpressionNode* condition, ExpressionNode* iter, StatementNode* statements, bool b, int start, int end) + { + ForNode* result = new (m_globalData) ForNode(m_globalData, initializer, condition, iter, statements, b); + result->setLoc(start, end); + return result; + } + + StatementNode* createForInLoop(const Identifier* ident, ExpressionNode* initializer, ExpressionNode* iter, StatementNode* statements, int start, int divot, int end, int initStart, int initEnd, int startLine, int endLine) + { + ForInNode* result = new (m_globalData) ForInNode(m_globalData, *ident, initializer, iter, statements, initStart, initStart - start, initEnd - initStart); + result->setLoc(startLine, endLine); + setExceptionLocation(result, start, divot + 1, end); + return result; + } + + StatementNode* createForInLoop(ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, int eStart, int eDivot, int eEnd, int start, int end) + { + ForInNode* result = new (m_globalData) ForInNode(m_globalData, lhs, iter, statements); + result->setLoc(start, end); + setExceptionLocation(result, eStart, eDivot, eEnd); + return result; + } + + StatementNode* createEmptyStatement() { return new (m_globalData) EmptyStatementNode(m_globalData); } + + StatementNode* createVarStatement(ExpressionNode* expr, int start, int end) + { + StatementNode* result; + if (!expr) + result = new (m_globalData) EmptyStatementNode(m_globalData); + else + result = new (m_globalData) VarStatementNode(m_globalData, expr); + result->setLoc(start, end); + return result; + } + + StatementNode* createReturnStatement(ExpressionNode* expression, int eStart, int eEnd, int startLine, int endLine) + { + ReturnNode* result = new (m_globalData) ReturnNode(m_globalData, expression); + setExceptionLocation(result, eStart, eEnd, eEnd); + result->setLoc(startLine, endLine); + return result; + } + + StatementNode* createBreakStatement(int eStart, int eEnd, int startLine, int endLine) + { + BreakNode* result = new (m_globalData) BreakNode(m_globalData); + setExceptionLocation(result, eStart, eEnd, eEnd); + result->setLoc(startLine, endLine); + return result; + } + + StatementNode* createBreakStatement(const Identifier* ident, int eStart, int eEnd, int startLine, int endLine) + { + BreakNode* result = new (m_globalData) BreakNode(m_globalData, *ident); + setExceptionLocation(result, eStart, eEnd, eEnd); + result->setLoc(startLine, endLine); + return result; + } + + StatementNode* createContinueStatement(int eStart, int eEnd, int startLine, int endLine) + { + ContinueNode* result = new (m_globalData) ContinueNode(m_globalData); + setExceptionLocation(result, eStart, eEnd, eEnd); + result->setLoc(startLine, endLine); + return result; + } + + StatementNode* createContinueStatement(const Identifier* ident, int eStart, int eEnd, int startLine, int endLine) + { + ContinueNode* result = new (m_globalData) ContinueNode(m_globalData, *ident); + setExceptionLocation(result, eStart, eEnd, eEnd); + result->setLoc(startLine, endLine); + return result; + } + + StatementNode* createTryStatement(StatementNode* tryBlock, const Identifier* ident, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine) + { + TryNode* result = new (m_globalData) TryNode(m_globalData, tryBlock, *ident, catchHasEval, catchBlock, finallyBlock); + if (catchBlock) + usesCatch(); + result->setLoc(startLine, endLine); + return result; + } + + StatementNode* createSwitchStatement(ExpressionNode* expr, ClauseListNode* firstClauses, CaseClauseNode* defaultClause, ClauseListNode* secondClauses, int startLine, int endLine) + { + CaseBlockNode* cases = new (m_globalData) CaseBlockNode(m_globalData, firstClauses, defaultClause, secondClauses); + SwitchNode* result = new (m_globalData) SwitchNode(m_globalData, expr, cases); + result->setLoc(startLine, endLine); + return result; + } + + StatementNode* createWhileStatement(ExpressionNode* expr, StatementNode* statement, int startLine, int endLine) + { + WhileNode* result = new (m_globalData) WhileNode(m_globalData, expr, statement); + result->setLoc(startLine, endLine); + return result; + } + + StatementNode* createDoWhileStatement(StatementNode* statement, ExpressionNode* expr, int startLine, int endLine) + { + DoWhileNode* result = new (m_globalData) DoWhileNode(m_globalData, statement, expr); + result->setLoc(startLine, endLine); + return result; + } + + StatementNode* createLabelStatement(const Identifier* ident, StatementNode* statement, int start, int end) + { + LabelNode* result = new (m_globalData) LabelNode(m_globalData, *ident, statement); + setExceptionLocation(result, start, end, end); + return result; + } + + StatementNode* createWithStatement(ExpressionNode* expr, StatementNode* statement, int start, int end, int startLine, int endLine) + { + usesWith(); + WithNode* result = new (m_globalData) WithNode(m_globalData, expr, statement, end, end - start); + result->setLoc(startLine, endLine); + return result; + } + + StatementNode* createThrowStatement(ExpressionNode* expr, int start, int end, int startLine, int endLine) + { + ThrowNode* result = new (m_globalData) ThrowNode(m_globalData, expr); + result->setLoc(startLine, endLine); + setExceptionLocation(result, start, end, end); + return result; + } + + StatementNode* createDebugger(int startLine, int endLine) + { + DebuggerStatementNode* result = new (m_globalData) DebuggerStatementNode(m_globalData); + result->setLoc(startLine, endLine); + return result; + } + + StatementNode* createConstStatement(ConstDeclNode* decls, int startLine, int endLine) + { + ConstStatementNode* result = new (m_globalData) ConstStatementNode(m_globalData, decls); + result->setLoc(startLine, endLine); + return result; + } + + ConstDeclNode* appendConstDecl(ConstDeclNode* tail, const Identifier* name, ExpressionNode* initializer) + { + ConstDeclNode* result = new (m_globalData) ConstDeclNode(m_globalData, *name, initializer); + if (tail) + tail->m_next = result; + return result; + } + + void appendStatement(JSC::SourceElements* elements, JSC::StatementNode* statement) + { + elements->append(statement); + } + + void addVar(const Identifier* ident, int attrs) + { + if (m_globalData->propertyNames->arguments == *ident) + usesArguments(); + m_scopes.last().m_varDeclarations->data.append(std::make_pair(ident, attrs)); + } + + ExpressionNode* combineCommaNodes(ExpressionNode* list, ExpressionNode* init) + { + if (!list) + return init; + if (list->isCommaNode()) { + static_cast<CommaNode*>(list)->append(init); + return list; + } + return new (m_globalData) CommaNode(m_globalData, list, init); + } + + int evalCount() const { return m_evalCount; } + + void appendBinaryExpressionInfo(int& operandStackDepth, ExpressionNode* current, int exprStart, int lhs, int rhs, bool hasAssignments) + { + operandStackDepth++; + m_binaryOperandStack.append(std::make_pair(current, BinaryOpInfo(exprStart, lhs, rhs, hasAssignments))); + } + + // Logic to handle datastructures used during parsing of binary expressions + void operatorStackPop(int& operatorStackDepth) + { + operatorStackDepth--; + m_binaryOperatorStack.removeLast(); + } + bool operatorStackHasHigherPrecedence(int&, int precedence) + { + return precedence <= m_binaryOperatorStack.last().second; + } + const BinaryOperand& getFromOperandStack(int i) { return m_binaryOperandStack[m_binaryOperandStack.size() + i]; } + void shrinkOperandStackBy(int& operandStackDepth, int amount) + { + operandStackDepth -= amount; + ASSERT(operandStackDepth >= 0); + m_binaryOperandStack.resize(m_binaryOperandStack.size() - amount); + } + void appendBinaryOperation(int& operandStackDepth, int&, const BinaryOperand& lhs, const BinaryOperand& rhs) + { + operandStackDepth++; + m_binaryOperandStack.append(std::make_pair(makeBinaryNode(m_binaryOperatorStack.last().first, lhs, rhs), BinaryOpInfo(lhs.second, rhs.second))); + } + void operatorStackAppend(int& operatorStackDepth, int op, int precedence) + { + operatorStackDepth++; + m_binaryOperatorStack.append(std::make_pair(op, precedence)); + } + ExpressionNode* popOperandStack(int&) + { + ExpressionNode* result = m_binaryOperandStack.last().first; + m_binaryOperandStack.removeLast(); + return result; + } + + void appendUnaryToken(int& tokenStackDepth, int type, int start) + { + tokenStackDepth++; + m_unaryTokenStack.append(std::make_pair(type, start)); + } + + int unaryTokenStackLastType(int&) + { + return m_unaryTokenStack.last().first; + } + + int unaryTokenStackLastStart(int&) + { + return m_unaryTokenStack.last().second; + } + + void unaryTokenStackRemoveLast(int& tokenStackDepth) + { + tokenStackDepth--; + m_unaryTokenStack.removeLast(); + } + + void assignmentStackAppend(int& assignmentStackDepth, ExpressionNode* node, int start, int divot, int assignmentCount, Operator op) + { + assignmentStackDepth++; + m_assignmentInfoStack.append(AssignmentInfo(node, start, divot, assignmentCount, op)); + } + + ExpressionNode* createAssignment(int& assignmentStackDepth, ExpressionNode* rhs, int initialAssignmentCount, int currentAssignmentCount, int lastTokenEnd) + { + ExpressionNode* result = makeAssignNode(m_assignmentInfoStack.last().m_node, m_assignmentInfoStack.last().m_op, rhs, m_assignmentInfoStack.last().m_initAssignments != initialAssignmentCount, m_assignmentInfoStack.last().m_initAssignments != currentAssignmentCount, m_assignmentInfoStack.last().m_start, m_assignmentInfoStack.last().m_divot + 1, lastTokenEnd); + m_assignmentInfoStack.removeLast(); + assignmentStackDepth--; + return result; + } + +private: + struct Scope { + Scope(JSGlobalData* globalData) + : m_varDeclarations(new (globalData) ParserArenaData<DeclarationStacks::VarStack>) + , m_funcDeclarations(new (globalData) ParserArenaData<DeclarationStacks::FunctionStack>) + , m_features(0) + , m_numConstants(0) + { + } + ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations; + ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations; + int m_features; + int m_numConstants; + }; + + static void setExceptionLocation(ThrowableExpressionData* node, unsigned start, unsigned divot, unsigned end) + { + node->setExceptionSourceCode(divot, divot - start, end - divot); + } + + void incConstants() { m_scopes.last().m_numConstants++; } + void usesThis() { m_scopes.last().m_features |= ThisFeature; } + void usesCatch() { m_scopes.last().m_features |= CatchFeature; } + void usesClosures() { m_scopes.last().m_features |= ClosureFeature; } + void usesArguments() { m_scopes.last().m_features |= ArgumentsFeature; } + void usesAssignment() { m_scopes.last().m_features |= AssignFeature; } + void usesWith() { m_scopes.last().m_features |= WithFeature; } + void usesEval() + { + m_evalCount++; + m_scopes.last().m_features |= EvalFeature; + } + ExpressionNode* createNumber(double d) + { + return new (m_globalData) NumberNode(m_globalData, d); + } + + JSGlobalData* m_globalData; + Lexer* m_lexer; + Vector<Scope> m_scopes; + Vector<BinaryOperand, 10> m_binaryOperandStack; + Vector<AssignmentInfo, 10> m_assignmentInfoStack; + Vector<pair<int, int>, 10> m_binaryOperatorStack; + Vector<pair<int, int>, 10> m_unaryTokenStack; + int m_evalCount; +}; + +ExpressionNode* ASTBuilder::makeTypeOfNode(ExpressionNode* expr) +{ + if (expr->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(expr); + return new (m_globalData) TypeOfResolveNode(m_globalData, resolve->identifier()); + } + return new (m_globalData) TypeOfValueNode(m_globalData, expr); +} + +ExpressionNode* ASTBuilder::makeDeleteNode(ExpressionNode* expr, int start, int divot, int end) +{ + if (!expr->isLocation()) + return new (m_globalData) DeleteValueNode(m_globalData, expr); + if (expr->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(expr); + return new (m_globalData) DeleteResolveNode(m_globalData, resolve->identifier(), divot, divot - start, end - divot); + } + if (expr->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); + return new (m_globalData) DeleteBracketNode(m_globalData, bracket->base(), bracket->subscript(), divot, divot - start, end - divot); + } + ASSERT(expr->isDotAccessorNode()); + DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr); + return new (m_globalData) DeleteDotNode(m_globalData, dot->base(), dot->identifier(), divot, divot - start, end - divot); +} + +ExpressionNode* ASTBuilder::makeNegateNode(ExpressionNode* n) +{ + if (n->isNumber()) { + NumberNode* numberNode = static_cast<NumberNode*>(n); + numberNode->setValue(-numberNode->value()); + return numberNode; + } + + return new (m_globalData) NegateNode(m_globalData, n); +} + +ExpressionNode* ASTBuilder::makeBitwiseNotNode(ExpressionNode* expr) +{ + if (expr->isNumber()) + return createNumber(~toInt32(static_cast<NumberNode*>(expr)->value())); + return new (m_globalData) BitwiseNotNode(m_globalData, expr); +} + +ExpressionNode* ASTBuilder::makeMultNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + expr1 = expr1->stripUnaryPlus(); + expr2 = expr2->stripUnaryPlus(); + + if (expr1->isNumber() && expr2->isNumber()) + return createNumber(static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value()); + + if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1) + return new (m_globalData) UnaryPlusNode(m_globalData, expr2); + + if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1) + return new (m_globalData) UnaryPlusNode(m_globalData, expr1); + + return new (m_globalData) MultNode(m_globalData, expr1, expr2, rightHasAssignments); +} + +ExpressionNode* ASTBuilder::makeDivNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + expr1 = expr1->stripUnaryPlus(); + expr2 = expr2->stripUnaryPlus(); + + if (expr1->isNumber() && expr2->isNumber()) + return createNumber(static_cast<NumberNode*>(expr1)->value() / static_cast<NumberNode*>(expr2)->value()); + return new (m_globalData) DivNode(m_globalData, expr1, expr2, rightHasAssignments); +} + +ExpressionNode* ASTBuilder::makeAddNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + if (expr1->isNumber() && expr2->isNumber()) + return createNumber(static_cast<NumberNode*>(expr1)->value() + static_cast<NumberNode*>(expr2)->value()); + return new (m_globalData) AddNode(m_globalData, expr1, expr2, rightHasAssignments); +} + +ExpressionNode* ASTBuilder::makeSubNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + expr1 = expr1->stripUnaryPlus(); + expr2 = expr2->stripUnaryPlus(); + + if (expr1->isNumber() && expr2->isNumber()) + return createNumber(static_cast<NumberNode*>(expr1)->value() - static_cast<NumberNode*>(expr2)->value()); + return new (m_globalData) SubNode(m_globalData, expr1, expr2, rightHasAssignments); +} + +ExpressionNode* ASTBuilder::makeLeftShiftNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + if (expr1->isNumber() && expr2->isNumber()) + return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) << (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f)); + return new (m_globalData) LeftShiftNode(m_globalData, expr1, expr2, rightHasAssignments); +} + +ExpressionNode* ASTBuilder::makeRightShiftNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + if (expr1->isNumber() && expr2->isNumber()) + return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f)); + return new (m_globalData) RightShiftNode(m_globalData, expr1, expr2, rightHasAssignments); +} + +ExpressionNode* ASTBuilder::makeFunctionCallNode(ExpressionNode* func, ArgumentsNode* args, int start, int divot, int end) +{ + if (!func->isLocation()) + return new (m_globalData) FunctionCallValueNode(m_globalData, func, args, divot, divot - start, end - divot); + if (func->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(func); + const Identifier& identifier = resolve->identifier(); + if (identifier == m_globalData->propertyNames->eval) { + usesEval(); + return new (m_globalData) EvalFunctionCallNode(m_globalData, args, divot, divot - start, end - divot); + } + return new (m_globalData) FunctionCallResolveNode(m_globalData, identifier, args, divot, divot - start, end - divot); + } + if (func->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func); + FunctionCallBracketNode* node = new (m_globalData) FunctionCallBracketNode(m_globalData, bracket->base(), bracket->subscript(), args, divot, divot - start, end - divot); + node->setSubexpressionInfo(bracket->divot(), bracket->endOffset()); + return node; + } + ASSERT(func->isDotAccessorNode()); + DotAccessorNode* dot = static_cast<DotAccessorNode*>(func); + FunctionCallDotNode* node; + if (dot->identifier() == m_globalData->propertyNames->call) + node = new (m_globalData) CallFunctionCallDotNode(m_globalData, dot->base(), dot->identifier(), args, divot, divot - start, end - divot); + else if (dot->identifier() == m_globalData->propertyNames->apply) + node = new (m_globalData) ApplyFunctionCallDotNode(m_globalData, dot->base(), dot->identifier(), args, divot, divot - start, end - divot); + else + node = new (m_globalData) FunctionCallDotNode(m_globalData, dot->base(), dot->identifier(), args, divot, divot - start, end - divot); + node->setSubexpressionInfo(dot->divot(), dot->endOffset()); + return node; +} + +ExpressionNode* ASTBuilder::makeBinaryNode(int token, pair<ExpressionNode*, BinaryOpInfo> lhs, pair<ExpressionNode*, BinaryOpInfo> rhs) +{ + switch (token) { + case OR: + return new (m_globalData) LogicalOpNode(m_globalData, lhs.first, rhs.first, OpLogicalOr); + + case AND: + return new (m_globalData) LogicalOpNode(m_globalData, lhs.first, rhs.first, OpLogicalAnd); + + case '|': + return new (m_globalData) BitOrNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case '^': + return new (m_globalData) BitXOrNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case '&': + return new (m_globalData) BitAndNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case EQEQ: + return new (m_globalData) EqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case NE: + return new (m_globalData) NotEqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case STREQ: + return new (m_globalData) StrictEqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case STRNEQ: + return new (m_globalData) NotStrictEqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case '<': + return new (m_globalData) LessNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case '>': + return new (m_globalData) GreaterNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case LE: + return new (m_globalData) LessEqNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case GE: + return new (m_globalData) GreaterEqNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case INSTANCEOF: { + InstanceOfNode* node = new (m_globalData) InstanceOfNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + setExceptionLocation(node, lhs.second.start, rhs.second.start, rhs.second.end); + return node; + } + + case INTOKEN: { + InNode* node = new (m_globalData) InNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + setExceptionLocation(node, lhs.second.start, rhs.second.start, rhs.second.end); + return node; + } + + case LSHIFT: + return makeLeftShiftNode(lhs.first, rhs.first, rhs.second.hasAssignment); + + case RSHIFT: + return makeRightShiftNode(lhs.first, rhs.first, rhs.second.hasAssignment); + + case URSHIFT: + return new (m_globalData) UnsignedRightShiftNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + + case '+': + return makeAddNode(lhs.first, rhs.first, rhs.second.hasAssignment); + + case '-': + return makeSubNode(lhs.first, rhs.first, rhs.second.hasAssignment); + + case '*': + return makeMultNode(lhs.first, rhs.first, rhs.second.hasAssignment); + + case '/': + return makeDivNode(lhs.first, rhs.first, rhs.second.hasAssignment); + + case '%': + return new (m_globalData) ModNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); + } + CRASH(); + return 0; +} + +ExpressionNode* ASTBuilder::makeAssignNode(ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end) +{ + usesAssignment(); + if (!loc->isLocation()) + return new (m_globalData) AssignErrorNode(m_globalData, loc, op, expr, divot, divot - start, end - divot); + + if (loc->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(loc); + if (op == OpEqual) { + AssignResolveNode* node = new (m_globalData) AssignResolveNode(m_globalData, resolve->identifier(), expr, exprHasAssignments); + setExceptionLocation(node, start, divot, end); + return node; + } + return new (m_globalData) ReadModifyResolveNode(m_globalData, resolve->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot); + } + if (loc->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc); + if (op == OpEqual) + return new (m_globalData) AssignBracketNode(m_globalData, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), bracket->divot() - start, end - bracket->divot()); + ReadModifyBracketNode* node = new (m_globalData) ReadModifyBracketNode(m_globalData, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, divot - start, end - divot); + node->setSubexpressionInfo(bracket->divot(), bracket->endOffset()); + return node; + } + ASSERT(loc->isDotAccessorNode()); + DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc); + if (op == OpEqual) + return new (m_globalData) AssignDotNode(m_globalData, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot()); + + ReadModifyDotNode* node = new (m_globalData) ReadModifyDotNode(m_globalData, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot); + node->setSubexpressionInfo(dot->divot(), dot->endOffset()); + return node; +} + +ExpressionNode* ASTBuilder::makePrefixNode(ExpressionNode* expr, Operator op, int start, int divot, int end) +{ + usesAssignment(); + if (!expr->isLocation()) + return new (m_globalData) PrefixErrorNode(m_globalData, expr, op, divot, divot - start, end - divot); + + if (expr->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(expr); + return new (m_globalData) PrefixResolveNode(m_globalData, resolve->identifier(), op, divot, divot - start, end - divot); + } + if (expr->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); + PrefixBracketNode* node = new (m_globalData) PrefixBracketNode(m_globalData, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot); + node->setSubexpressionInfo(bracket->divot(), bracket->startOffset()); + return node; + } + ASSERT(expr->isDotAccessorNode()); + DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr); + PrefixDotNode* node = new (m_globalData) PrefixDotNode(m_globalData, dot->base(), dot->identifier(), op, divot, divot - start, end - divot); + node->setSubexpressionInfo(dot->divot(), dot->startOffset()); + return node; +} + +ExpressionNode* ASTBuilder::makePostfixNode(ExpressionNode* expr, Operator op, int start, int divot, int end) +{ + usesAssignment(); + if (!expr->isLocation()) + return new (m_globalData) PostfixErrorNode(m_globalData, expr, op, divot, divot - start, end - divot); + + if (expr->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(expr); + return new (m_globalData) PostfixResolveNode(m_globalData, resolve->identifier(), op, divot, divot - start, end - divot); + } + if (expr->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); + PostfixBracketNode* node = new (m_globalData) PostfixBracketNode(m_globalData, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot); + node->setSubexpressionInfo(bracket->divot(), bracket->endOffset()); + return node; + + } + ASSERT(expr->isDotAccessorNode()); + DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr); + PostfixDotNode* node = new (m_globalData) PostfixDotNode(m_globalData, dot->base(), dot->identifier(), op, divot, divot - start, end - divot); + node->setSubexpressionInfo(dot->divot(), dot->endOffset()); + return node; +} + +} + +#endif diff --git a/JavaScriptCore/parser/JSParser.cpp b/JavaScriptCore/parser/JSParser.cpp new file mode 100644 index 0000000..1934c0c --- /dev/null +++ b/JavaScriptCore/parser/JSParser.cpp @@ -0,0 +1,1504 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(RECURSIVE_PARSE) +#include "JSParser.h" + +using namespace JSC; + +#include "JSGlobalData.h" +#include "NodeInfo.h" +#include "Grammar.h" +#include "ASTBuilder.h" +#include <utility> + +using namespace std; + +namespace JSC { +#define fail() do { m_error = true; return 0; } while (0) +#define failIfFalse(cond) do { if (!(cond)) fail(); } while (0) +#define failIfTrue(cond) do { if ((cond)) fail(); } while (0) +#define consumeOrFail(tokenType) do { if (!consume(tokenType)) fail(); } while (0) +#define matchOrFail(tokenType) do { if (!match(tokenType)) fail(); } while (0) +#define failIfStackOverflow() do { failIfFalse(canRecurse()); } while (0) + +// Macros to make the more common TreeBuilder types a little less verbose +#define TreeStatement typename TreeBuilder::Statement +#define TreeExpression typename TreeBuilder::Expression +#define TreeFormalParameterList typename TreeBuilder::FormalParameterList +#define TreeSourceElements typename TreeBuilder::SourceElements +#define TreeClause typename TreeBuilder::Clause +#define TreeClauseList typename TreeBuilder::ClauseList +#define TreeConstDeclList typename TreeBuilder::ConstDeclList +#define TreeArguments typename TreeBuilder::Arguments +#define TreeArgumentsList typename TreeBuilder::ArgumentsList +#define TreeFunctionBody typename TreeBuilder::FunctionBody +#define TreeProperty typename TreeBuilder::Property +#define TreePropertyList typename TreeBuilder::PropertyList + +// This matches v8 +static const ptrdiff_t kMaxParserStackUsage = 128 * sizeof(void*) * 1024; + +class JSParser { +public: + JSParser(Lexer*, JSGlobalData*); + bool parseProgram(); +private: + struct AllowInOverride { + AllowInOverride(JSParser* parser) + : m_parser(parser) + , m_oldAllowsIn(parser->m_allowsIn) + { + parser->m_allowsIn = true; + } + ~AllowInOverride() + { + m_parser->m_allowsIn = m_oldAllowsIn; + } + JSParser* m_parser; + bool m_oldAllowsIn; + }; + + const JSToken& token() { return m_token; } + void next() + { + m_lastLine = token().m_info.last_line; + m_lastTokenEnd = token().m_info.last_column; + m_lexer->setLastLineNumber(m_lastLine); + m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info); + m_tokenCount++; + } + + bool consume(int expected) + { + bool result = m_token.m_type == expected; + failIfFalse(result); + next(); + return result; + } + + bool match(int expected) + { + return m_token.m_type == expected; + } + + int tokenStart() + { + return token().m_info.first_column; + } + + int tokenLine() + { + return token().m_info.first_line; + } + + int tokenEnd() + { + return token().m_info.last_column; + } + + template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseForStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseBreakStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseContinueStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseReturnStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseThrowStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseWithStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseSwitchStatement(TreeBuilder&); + template <class TreeBuilder> TreeClauseList parseSwitchClauses(TreeBuilder&); + template <class TreeBuilder> TreeClause parseSwitchDefaultClause(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseTryStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseDebuggerStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&); + template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeStatement parseBlockStatement(TreeBuilder&); + template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&); + template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&); + template <class TreeBuilder> TreeExpression parseMemberExpression(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&, bool& usesArguments); + template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd); + template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context); + enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName }; + template <FunctionRequirements, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine); + int isBinaryOperator(int token); + bool allowAutomaticSemicolon(); + + bool autoSemiColon() + { + if (token().m_type == ';') { + next(); + return true; + } + return allowAutomaticSemicolon(); + } + + bool canRecurse() + { + char sample = 0; + ASSERT(m_endAddress); + return &sample > m_endAddress; + } + + int lastTokenEnd() const + { + return m_lastTokenEnd; + } + + ParserArena m_arena; + Lexer* m_lexer; + char* m_endAddress; + bool m_error; + JSGlobalData* m_globalData; + JSToken m_token; + bool m_allowsIn; + int m_tokenCount; + int m_lastLine; + int m_lastTokenEnd; + int m_assignmentCount; + int m_nonLHSCount; +}; + +int jsParse(JSGlobalData* globalData) +{ + JSParser parser(globalData->lexer, globalData); + return parser.parseProgram(); +} + +JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData) + : m_lexer(lexer) + , m_endAddress(0) + , m_error(false) + , m_globalData(globalData) + , m_allowsIn(true) + , m_tokenCount(0) + , m_lastLine(0) + , m_lastTokenEnd(0) + , m_assignmentCount(0) + , m_nonLHSCount(0) +{ + m_endAddress = *(globalData->stackGuards); + if (!m_endAddress) { + char sample = 0; + m_endAddress = &sample - kMaxParserStackUsage; + *(globalData->stackGuards) = m_endAddress; + } + next(); + m_lexer->setLastLineNumber(tokenLine()); +} + +bool JSParser::parseProgram() +{ + ASTBuilder context(m_globalData, m_lexer); + SourceElements* sourceElements = parseSourceElements<ASTBuilder>(context); + if (!sourceElements || !consume(0)) + return true; + m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features(), + m_lastLine, context.numConstants()); + return false; +} + +bool JSParser::allowAutomaticSemicolon() +{ + return match(CLOSEBRACE) || match(0) || m_lexer->prevTerminator(); +} + +template <class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context) +{ + TreeSourceElements sourceElements = context.createSourceElements(); + while (TreeStatement statement = parseStatement(context)) + context.appendStatement(sourceElements, statement); + + if (m_error) + fail(); + return sourceElements; +} + +template <class TreeBuilder> TreeStatement JSParser::parseVarDeclaration(TreeBuilder& context) +{ + ASSERT(match(VAR)); + int start = tokenLine(); + int end = 0; + int scratch; + const Identifier* scratch1 = 0; + TreeExpression scratch2 = 0; + int scratch3 = 0; + TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3); + failIfTrue(m_error); + failIfFalse(autoSemiColon()); + + return context.createVarStatement(varDecls, start, end); +} + +template <class TreeBuilder> TreeStatement JSParser::parseConstDeclaration(TreeBuilder& context) +{ + ASSERT(match(CONSTTOKEN)); + int start = tokenLine(); + int end = 0; + TreeConstDeclList constDecls = parseConstDeclarationList(context); + failIfTrue(m_error); + failIfFalse(autoSemiColon()); + + return context.createConstStatement(constDecls, start, end); +} + +template <class TreeBuilder> TreeStatement JSParser::parseDoWhileStatement(TreeBuilder& context) +{ + ASSERT(match(DO)); + int startLine = tokenLine(); + next(); + TreeStatement statement = parseStatement(context); + failIfFalse(statement); + int endLine = tokenLine(); + consumeOrFail(WHILE); + consumeOrFail('('); + TreeExpression expr = parseExpression(context); + failIfFalse(expr); + consumeOrFail(')'); + if (match(';')) + next(); // Always performs automatic semicolon insertion. + return context.createDoWhileStatement(statement, expr, startLine, endLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseWhileStatement(TreeBuilder& context) +{ + ASSERT(match(WHILE)); + int startLine = tokenLine(); + next(); + consumeOrFail('('); + TreeExpression expr = parseExpression(context); + failIfFalse(expr); + int endLine = tokenLine(); + consumeOrFail(')'); + TreeStatement statement = parseStatement(context); + failIfFalse(statement); + return context.createWhileStatement(expr, statement, startLine, endLine); +} + +template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(TreeBuilder& context, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd) +{ + TreeExpression varDecls = 0; + do { + declarations++; + next(); + matchOrFail(IDENT); + + int varStart = tokenStart(); + identStart = varStart; + const Identifier* name = token().m_data.ident; + lastIdent = name; + next(); + bool hasInitializer = match('='); + context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0); + if (hasInitializer) { + int varDivot = tokenStart() + 1; + initStart = tokenStart(); + next(); // consume '=' + int initialAssignments = m_assignmentCount; + TreeExpression initializer = parseAssignmentExpression(context); + initEnd = lastTokenEnd(); + lastInitializer = initializer; + failIfFalse(initializer); + + TreeExpression node = context.createAssignResolve(*name, initializer, initialAssignments != m_assignmentCount, varStart, varDivot, lastTokenEnd()); + if (!varDecls) + varDecls = node; + else + varDecls = context.combineCommaNodes(varDecls, node); + } + } while (match(',')); + return varDecls; +} + +template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationList(TreeBuilder& context) +{ + TreeConstDeclList constDecls = 0; + TreeConstDeclList tail = 0; + do { + next(); + matchOrFail(IDENT); + const Identifier* name = token().m_data.ident; + next(); + bool hasInitializer = match('='); + context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0)); + TreeExpression initializer = 0; + if (hasInitializer) { + next(); // consume '=' + initializer = parseAssignmentExpression(context); + } + tail = context.appendConstDecl(tail, name, initializer); + if (!constDecls) + constDecls = tail; + } while (match(',')); + return constDecls; +} + +template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuilder& context) +{ + ASSERT(match(FOR)); + int startLine = tokenLine(); + next(); + consumeOrFail('('); + int nonLHSCount = m_nonLHSCount; + int declarations = 0; + int declsStart = 0; + int declsEnd = 0; + TreeExpression decls = 0; + bool hasDeclaration = false; + if (match(VAR)) { + /* + for (var IDENT in expression) statement + for (var IDENT = expression in expression) statement + for (var varDeclarationList; expressionOpt; expressionOpt) + */ + hasDeclaration = true; + const Identifier* forInTarget = 0; + TreeExpression forInInitializer = 0; + m_allowsIn = false; + int initStart = 0; + int initEnd = 0; + decls = parseVarDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd); + m_allowsIn = true; + if (m_error) + fail(); + + // Remainder of a standard for loop is handled identically + if (declarations > 1 || match(';')) + goto standardForLoop; + + // Handle for-in with var declaration + int inLocation = tokenStart(); + if (!consume(INTOKEN)) + fail(); + + TreeExpression expr = parseExpression(context); + failIfFalse(expr); + int exprEnd = lastTokenEnd(); + + int endLine = tokenLine(); + consumeOrFail(')'); + + TreeStatement statement = parseStatement(context); + failIfFalse(statement); + + return context.createForInLoop(forInTarget, forInInitializer, expr, statement, declsStart, inLocation, exprEnd, initStart, initEnd, startLine, endLine); + } + + if (!match(';')) { + m_allowsIn = false; + declsStart = tokenStart(); + decls = parseExpression(context); + declsEnd = lastTokenEnd(); + m_allowsIn = true; + failIfFalse(decls); + } + + if (match(';')) { + standardForLoop: + // Standard for loop + next(); + TreeExpression condition = 0; + + if (!match(';')) { + condition = parseExpression(context); + failIfFalse(condition); + } + consumeOrFail(';'); + + TreeExpression increment = 0; + if (!match(')')) { + increment = parseExpression(context); + failIfFalse(increment); + } + int endLine = tokenLine(); + consumeOrFail(')'); + TreeStatement statement = parseStatement(context); + failIfFalse(statement); + return context.createForLoop(decls, condition, increment, statement, hasDeclaration, startLine, endLine); + } + + // For-in loop + failIfFalse(nonLHSCount == m_nonLHSCount); + consumeOrFail(INTOKEN); + TreeExpression expr = parseExpression(context); + failIfFalse(expr); + int exprEnd = lastTokenEnd(); + int endLine = tokenLine(); + consumeOrFail(')'); + TreeStatement statement = parseStatement(context); + failIfFalse(statement); + + return context.createForInLoop(decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseBreakStatement(TreeBuilder& context) +{ + ASSERT(match(BREAK)); + int startCol = tokenStart(); + int endCol = tokenEnd(); + int startLine = tokenLine(); + int endLine = tokenLine(); + next(); + + if (autoSemiColon()) + return context.createBreakStatement(startCol, endCol, startLine, endLine); + matchOrFail(IDENT); + const Identifier* ident = token().m_data.ident; + endCol = tokenEnd(); + endLine = tokenLine(); + next(); + failIfFalse(autoSemiColon()); + return context.createBreakStatement(ident, startCol, endCol, startLine, endLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseContinueStatement(TreeBuilder& context) +{ + ASSERT(match(CONTINUE)); + int startCol = tokenStart(); + int endCol = tokenEnd(); + int startLine = tokenLine(); + int endLine = tokenLine(); + next(); + + if (autoSemiColon()) + return context.createContinueStatement(startCol, endCol, startLine, endLine); + matchOrFail(IDENT); + const Identifier* ident = token().m_data.ident; + endCol = tokenEnd(); + endLine = tokenLine(); + next(); + failIfFalse(autoSemiColon()); + return context.createContinueStatement(ident, startCol, endCol, startLine, endLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseReturnStatement(TreeBuilder& context) +{ + ASSERT(match(RETURN)); + int startLine = tokenLine(); + int endLine = startLine; + int start = tokenStart(); + int end = tokenEnd(); + next(); + // We do the auto semicolon check before attempting to parse an expression + // as we need to ensure the a line break after the return correctly terminates + // the statement + if (match(';')) + endLine = tokenLine(); + if (autoSemiColon()) + return context.createReturnStatement(0, start, end, startLine, endLine); + TreeExpression expr = parseExpression(context); + failIfFalse(expr); + end = lastTokenEnd(); + if (match(';')) + endLine = tokenLine(); + failIfFalse(autoSemiColon()); + return context.createReturnStatement(expr, start, end, startLine, endLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseThrowStatement(TreeBuilder& context) +{ + ASSERT(match(THROW)); + int eStart = tokenStart(); + int startLine = tokenLine(); + next(); + + TreeExpression expr = parseExpression(context); + failIfFalse(expr); + int eEnd = lastTokenEnd(); + int endLine = tokenLine(); + failIfFalse(autoSemiColon()); + + return context.createThrowStatement(expr, eStart, eEnd, startLine, endLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuilder& context) +{ + ASSERT(match(WITH)); + int startLine = tokenLine(); + next(); + consumeOrFail('('); + int start = tokenStart(); + TreeExpression expr = parseExpression(context); + failIfFalse(expr); + int end = lastTokenEnd(); + + int endLine = tokenLine(); + consumeOrFail(')'); + + TreeStatement statement = parseStatement(context); + failIfFalse(statement); + + return context.createWithStatement(expr, statement, start, end, startLine, endLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseSwitchStatement(TreeBuilder& context) +{ + ASSERT(match(SWITCH)); + int startLine = tokenLine(); + next(); + consumeOrFail('('); + TreeExpression expr = parseExpression(context); + failIfFalse(expr); + int endLine = tokenLine(); + consumeOrFail(')'); + consumeOrFail(OPENBRACE); + + TreeClauseList firstClauses = parseSwitchClauses(context); + failIfTrue(m_error); + + TreeClause defaultClause = parseSwitchDefaultClause(context); + failIfTrue(m_error); + + TreeClauseList secondClauses = parseSwitchClauses(context); + failIfTrue(m_error); + consumeOrFail(CLOSEBRACE); + + return context.createSwitchStatement(expr, firstClauses, defaultClause, secondClauses, startLine, endLine); + +} + +template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBuilder& context) +{ + if (!match(CASE)) + return 0; + next(); + TreeExpression condition = parseExpression(context); + failIfFalse(condition); + consumeOrFail(':'); + TreeSourceElements statements = parseSourceElements(context); + failIfFalse(statements); + TreeClause clause = context.createClause(condition, statements); + TreeClauseList clauseList = context.createClauseList(clause); + TreeClauseList tail = clauseList; + + while (match(CASE)) { + next(); + TreeExpression condition = parseExpression(context); + failIfFalse(condition); + consumeOrFail(':'); + TreeSourceElements statements = parseSourceElements(context); + failIfFalse(statements); + clause = context.createClause(condition, statements); + tail = context.createClauseList(tail, clause); + } + return clauseList; +} + +template <class TreeBuilder> TreeClause JSParser::parseSwitchDefaultClause(TreeBuilder& context) +{ + if (!match(DEFAULT)) + return 0; + next(); + consumeOrFail(':'); + TreeSourceElements statements = parseSourceElements(context); + failIfFalse(statements); + return context.createClause(0, statements); +} + +template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuilder& context) +{ + ASSERT(match(TRY)); + TreeStatement tryBlock = 0; + const Identifier* ident = &m_globalData->propertyNames->nullIdentifier; + bool catchHasEval = false; + TreeStatement catchBlock = 0; + TreeStatement finallyBlock = 0; + int firstLine = tokenLine(); + next(); + matchOrFail(OPENBRACE); + + tryBlock = parseBlockStatement(context); + failIfFalse(tryBlock); + int lastLine = m_lastLine; + + if (match(CATCH)) { + next(); + consumeOrFail('('); + matchOrFail(IDENT); + ident = token().m_data.ident; + next(); + consumeOrFail(')'); + matchOrFail(OPENBRACE); + int initialEvalCount = context.evalCount(); + catchBlock = parseBlockStatement(context); + failIfFalse(catchBlock); + catchHasEval = initialEvalCount != context.evalCount(); + } + + if (match(FINALLY)) { + next(); + matchOrFail(OPENBRACE); + finallyBlock = parseBlockStatement(context); + failIfFalse(finallyBlock); + } + failIfFalse(catchBlock || finallyBlock); + return context.createTryStatement(tryBlock, ident, catchHasEval, catchBlock, finallyBlock, firstLine, lastLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseDebuggerStatement(TreeBuilder& context) +{ + ASSERT(match(DEBUGGER)); + int startLine = tokenLine(); + int endLine = startLine; + next(); + if (match(';')) + startLine = tokenLine(); + failIfFalse(autoSemiColon()); + return context.createDebugger(startLine, endLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseBlockStatement(TreeBuilder& context) +{ + ASSERT(match(OPENBRACE)); + int start = tokenLine(); + next(); + if (match(CLOSEBRACE)) { + next(); + return context.createBlockStatement(0, start, m_lastLine); + } + TreeSourceElements subtree = parseSourceElements(context); + failIfFalse(subtree); + matchOrFail(CLOSEBRACE); + next(); + return context.createBlockStatement(subtree, start, m_lastLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context) +{ + failIfStackOverflow(); + switch (token().m_type) { + case OPENBRACE: + return parseBlockStatement(context); + case VAR: + return parseVarDeclaration(context); + case CONSTTOKEN: + return parseConstDeclaration(context); + case FUNCTION: + return parseFunctionDeclaration(context); + case ';': + next(); + return context.createEmptyStatement(); + case IF: + return parseIfStatement(context); + case DO: + return parseDoWhileStatement(context); + case WHILE: + return parseWhileStatement(context); + case FOR: + return parseForStatement(context); + case CONTINUE: + return parseContinueStatement(context); + case BREAK: + return parseBreakStatement(context); + case RETURN: + return parseReturnStatement(context); + case WITH: + return parseWithStatement(context); + case SWITCH: + return parseSwitchStatement(context); + case THROW: + return parseThrowStatement(context); + case TRY: + return parseTryStatement(context); + case DEBUGGER: + return parseDebuggerStatement(context); + case 0: + case CASE: + case CLOSEBRACE: + case DEFAULT: + // These tokens imply the end of a set of source elements + return 0; + case IDENT: + return parseExpressionOrLabelStatement(context); + default: + return parseExpressionStatement(context); + } +} + +template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParameters(TreeBuilder& context, bool& usesArguments) +{ + matchOrFail(IDENT); + usesArguments = m_globalData->propertyNames->arguments == *token().m_data.ident; + TreeFormalParameterList list = context.createFormalParameterList(*token().m_data.ident); + TreeFormalParameterList tail = list; + next(); + while (match(',')) { + next(); + matchOrFail(IDENT); + const Identifier* ident = token().m_data.ident; + next(); + usesArguments = usesArguments || m_globalData->propertyNames->arguments == *ident; + tail = context.createFormalParameterList(tail, *ident); + } + return list; +} + +template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBuilder& context) +{ + if (match(CLOSEBRACE)) + return context.createFunctionBody(); + typename TreeBuilder::FunctionBodyBuilder bodyBuilder(m_globalData, m_lexer); + failIfFalse(parseSourceElements(bodyBuilder)); + return context.createFunctionBody(); +} + +template <JSParser::FunctionRequirements requirements, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine) +{ + if (match(IDENT)) { + name = token().m_data.ident; + next(); + } else if (requirements == FunctionNeedsName) + return false; + consumeOrFail('('); + bool usesArguments = false; + if (!match(')')) { + parameters = parseFormalParameters(context, usesArguments); + failIfFalse(parameters); + } + consumeOrFail(')'); + matchOrFail(OPENBRACE); + + openBracePos = token().m_data.intValue; + bodyStartLine = tokenLine(); + next(); + + body = parseFunctionBody(context); + failIfFalse(body); + if (usesArguments) + context.setUsesArguments(body); + + matchOrFail(CLOSEBRACE); + closeBracePos = token().m_data.intValue; + next(); + return true; +} + +template <class TreeBuilder> TreeStatement JSParser::parseFunctionDeclaration(TreeBuilder& context) +{ + ASSERT(match(FUNCTION)); + next(); + const Identifier* name = 0; + TreeFormalParameterList parameters = 0; + TreeFunctionBody body = 0; + int openBracePos = 0; + int closeBracePos = 0; + int bodyStartLine = 0; + failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)); + failIfFalse(name); + return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseExpressionOrLabelStatement(TreeBuilder& context) +{ + + /* Expression and Label statements are ambiguous at LL(1), to avoid + * the cost of having a token buffer to support LL(2) we simply assume + * we have an expression statement, and then only look for a label if that + * parse fails. + */ + int start = tokenStart(); + int startLine = tokenLine(); + const Identifier* ident = token().m_data.ident; + int currentToken = m_tokenCount; + TreeExpression expression = parseExpression(context); + failIfFalse(expression); + if (autoSemiColon()) + return context.createExprStatement(expression, startLine, m_lastLine); + failIfFalse(currentToken + 1 == m_tokenCount); + int end = tokenEnd(); + consumeOrFail(':'); + TreeStatement statement = parseStatement(context); + failIfFalse(statement); + return context.createLabelStatement(ident, statement, start, end); +} + +template <class TreeBuilder> TreeStatement JSParser::parseExpressionStatement(TreeBuilder& context) +{ + int startLine = tokenLine(); + TreeExpression expression = parseExpression(context); + failIfFalse(expression); + failIfFalse(autoSemiColon()); + return context.createExprStatement(expression, startLine, m_lastLine); +} + +template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilder& context) +{ + ASSERT(match(IF)); + + int start = tokenLine(); + next(); + + consumeOrFail('('); + + TreeExpression condition = parseExpression(context); + failIfFalse(condition); + int end = tokenLine(); + consumeOrFail(')'); + + TreeStatement trueBlock = parseStatement(context); + failIfFalse(trueBlock); + + if (!match(ELSE)) + return context.createIfStatement(condition, trueBlock, start, end); + + Vector<TreeExpression> exprStack; + Vector<pair<int, int> > posStack; + Vector<TreeStatement> statementStack; + bool trailingElse = false; + do { + next(); + if (!match(IF)) { + TreeStatement block = parseStatement(context); + failIfFalse(block); + statementStack.append(block); + trailingElse = true; + break; + } + int innerStart = tokenLine(); + next(); + + consumeOrFail('('); + + TreeExpression innerCondition = parseExpression(context); + failIfFalse(innerCondition); + int innerEnd = tokenLine(); + consumeOrFail(')'); + + TreeStatement innerTrueBlock = parseStatement(context); + failIfFalse(innerTrueBlock); + exprStack.append(innerCondition); + posStack.append(make_pair(innerStart, innerEnd)); + statementStack.append(innerTrueBlock); + } while (match(ELSE)); + + if (!trailingElse) { + TreeExpression condition = exprStack.last(); + exprStack.removeLast(); + TreeStatement trueBlock = statementStack.last(); + statementStack.removeLast(); + pair<int, int> pos = posStack.last(); + posStack.removeLast(); + statementStack.append(context.createIfStatement(condition, trueBlock, pos.first, pos.second)); + } + + while (!exprStack.isEmpty()) { + TreeExpression condition = exprStack.last(); + exprStack.removeLast(); + TreeStatement falseBlock = statementStack.last(); + statementStack.removeLast(); + TreeStatement trueBlock = statementStack.last(); + statementStack.removeLast(); + pair<int, int> pos = posStack.last(); + posStack.removeLast(); + statementStack.append(context.createIfStatement(condition, trueBlock, falseBlock, pos.first, pos.second)); + } + + return context.createIfStatement(condition, trueBlock, statementStack.last(), start, end); +} + +template <class TreeBuilder> TreeExpression JSParser::parseExpression(TreeBuilder& context) +{ + failIfStackOverflow(); + TreeExpression node = parseAssignmentExpression(context); + failIfFalse(node); + if (!match(',')) + return node; + next(); + m_nonLHSCount++; + TreeExpression right = parseAssignmentExpression(context); + failIfFalse(right); + typename TreeBuilder::Comma commaNode = context.createCommaExpr(node, right); + while (match(',')) { + next(); + right = parseAssignmentExpression(context); + failIfFalse(right); + context.appendToComma(commaNode, right); + } + return commaNode; +} + + +template <typename TreeBuilder> TreeExpression JSParser::parseAssignmentExpression(TreeBuilder& context) +{ + failIfStackOverflow(); + int start = tokenStart(); + int initialAssignmentCount = m_assignmentCount; + int initialNonLHSCount = m_nonLHSCount; + TreeExpression lhs = parseConditionalExpression(context); + failIfFalse(lhs); + if (initialNonLHSCount != m_nonLHSCount) + return lhs; + + int assignmentStack = 0; + Operator op; + bool hadAssignment = false; + while (true) { + switch (token().m_type) { + case '=': op = OpEqual; break; + case PLUSEQUAL: op = OpPlusEq; break; + case MINUSEQUAL: op = OpMinusEq; break; + case MULTEQUAL: op = OpMultEq; break; + case DIVEQUAL: op = OpDivEq; break; + case LSHIFTEQUAL: op = OpLShift; break; + case RSHIFTEQUAL: op = OpRShift; break; + case URSHIFTEQUAL: op = OpURShift; break; + case ANDEQUAL: op = OpAndEq; break; + case XOREQUAL: op = OpXOrEq; break; + case OREQUAL: op = OpOrEq; break; + case MODEQUAL: op = OpModEq; break; + default: + goto end; + } + hadAssignment = true; + context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), m_assignmentCount, op); + start = tokenStart(); + m_assignmentCount++; + next(); + lhs = parseConditionalExpression(context); + failIfFalse(lhs); + if (initialNonLHSCount != m_nonLHSCount) + break; + } +end: + if (hadAssignment) + m_nonLHSCount++; + + if (!ASTBuilder::CreatesAST) + return lhs; + + while (assignmentStack) + lhs = context.createAssignment(assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEnd()); + + return lhs; +} + +template <class TreeBuilder> TreeExpression JSParser::parseConditionalExpression(TreeBuilder& context) +{ + TreeExpression cond = parseBinaryExpression(context); + failIfFalse(cond); + if (!match('?')) + return cond; + m_nonLHSCount++; + next(); + TreeExpression lhs = parseAssignmentExpression(context); + consumeOrFail(':'); + + TreeExpression rhs = parseAssignmentExpression(context); + failIfFalse(rhs); + return context.createConditionalExpr(cond, lhs, rhs); +} + +static bool isUnaryOp(int token) +{ + switch (token) { + case '!': + case '~': + case '-': + case '+': + case PLUSPLUS: + case AUTOPLUSPLUS: + case MINUSMINUS: + case AUTOMINUSMINUS: + case TYPEOF: + case VOIDTOKEN: + case DELETETOKEN: + return true; + default: + return false; + } +} + +int JSParser::isBinaryOperator(int token) +{ + switch (token) { + case OR: + return 1; + + case AND: + return 2; + + case '|': + return 3; + + case '^': + return 4; + + case '&': + return 5; + + case EQEQ: + case NE: + case STREQ: + case STRNEQ: + return 6; + + case '<': + case '>': + case LE: + case GE: + case INSTANCEOF: + return 7; + + case INTOKEN: + // same precedence as the above but needs a validity check + if (m_allowsIn) + return 7; + return 0; + + case LSHIFT: + case RSHIFT: + case URSHIFT: + return 8; + + case '+': + case '-': + return 9; + + case '*': + case '/': + case '%': + return 10; + + default: + return 0; + } +} + +template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(TreeBuilder& context) +{ + + int operandStackDepth = 0; + int operatorStackDepth = 0; + while (true) { + int exprStart = tokenStart(); + int initialAssignments = m_assignmentCount; + TreeExpression current = parseUnaryExpression(context); + failIfFalse(current); + + context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEnd(), lastTokenEnd(), initialAssignments != m_assignmentCount); + int precedence = isBinaryOperator(token().m_type); + if (!precedence) + break; + m_nonLHSCount++; + int operatorToken = token().m_type; + next(); + + while (operatorStackDepth && context.operatorStackHasHigherPrecedence(operatorStackDepth, precedence)) { + ASSERT(operandStackDepth > 1); + + typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1); + typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2); + context.shrinkOperandStackBy(operandStackDepth, 2); + context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs); + context.operatorStackPop(operatorStackDepth); + } + context.operatorStackAppend(operatorStackDepth, operatorToken, precedence); + } + + while (operatorStackDepth) { + ASSERT(operandStackDepth > 1); + + typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1); + typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2); + context.shrinkOperandStackBy(operandStackDepth, 2); + context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs); + context.operatorStackPop(operatorStackDepth); + } + return context.popOperandStack(operandStackDepth); +} + + +template <class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& context) +{ + bool wasIdent = false; + switch (token().m_type) { + case IDENT: + wasIdent = true; + case STRING: { + const Identifier* ident = token().m_data.ident; + next(); + if (match(':')) { + next(); + TreeExpression node = parseAssignmentExpression(context); + failIfFalse(node); + return context.createProperty(ident, node, PropertyNode::Constant); + } + failIfFalse(wasIdent); + matchOrFail(IDENT); + const Identifier* accessorName = 0; + TreeFormalParameterList parameters = 0; + TreeFunctionBody body = 0; + int openBracePos = 0; + int closeBracePos = 0; + int bodyStartLine = 0; + failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine)); + return context.createGetterOrSetterProperty(ident, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine); + } + case NUMBER: { + double propertyName = token().m_data.doubleValue; + next(); + consumeOrFail(':'); + TreeExpression node = parseAssignmentExpression(context); + failIfFalse(node); + return context.createProperty(propertyName, node, PropertyNode::Constant); + } + } + fail(); +} + +template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBuilder& context) +{ + consumeOrFail(OPENBRACE); + + if (match(CLOSEBRACE)) { + next(); + return context.createObjectLiteral(); + } + + TreeProperty property = parseProperty(context); + failIfFalse(property); + + TreePropertyList propertyList = context.createPropertyList(property); + TreePropertyList tail = propertyList; + + while (match(',')) { + next(); + // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 + if (match(CLOSEBRACE)) + break; + property = parseProperty(context); + failIfFalse(property); + + tail = context.createPropertyList(property, tail); + } + + consumeOrFail(CLOSEBRACE); + + return context.createObjectLiteral(propertyList); +} + +template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuilder& context) +{ + consumeOrFail('['); + + int elisions = 0; + while (match(',')) { + next(); + elisions++; + } + if (match(']')) { + next(); + return context.createArray(elisions); + } + + TreeExpression elem = parseAssignmentExpression(context); + failIfFalse(elem); + typename TreeBuilder::ElementList elementList = context.createElementList(elisions, elem); + typename TreeBuilder::ElementList tail = elementList; + elisions = 0; + while (match(',')) { + next(); + elisions = 0; + + while (match(',')) { + next(); + elisions++; + } + + if (match(']')) { + next(); + return context.createArray(elisions, elementList); + } + TreeExpression elem = parseAssignmentExpression(context); + failIfFalse(elem); + tail = context.createElementList(tail, elisions, elem); + } + + consumeOrFail(']'); + + return context.createArray(elementList); +} + +template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(TreeBuilder& context) +{ + switch (token().m_type) { + case OPENBRACE: + return parseObjectLiteral(context); + case '[': + return parseArrayLiteral(context); + case '(': { + next(); + int oldNonLHSCount = m_nonLHSCount; + TreeExpression result = parseExpression(context); + m_nonLHSCount = oldNonLHSCount; + consumeOrFail(')'); + + return result; + } + case THISTOKEN: { + next(); + return context.thisExpr(); + } + case IDENT: { + int start = tokenStart(); + const Identifier* ident = token().m_data.ident; + next(); + return context.createResolve(ident, start); + } + case STRING: { + const Identifier* ident = token().m_data.ident; + next(); + return context.createString(ident); + } + case NUMBER: { + double d = token().m_data.doubleValue; + next(); + return context.createNumberExpr(d); + } + case NULLTOKEN: { + next(); + return context.createNull(); + } + case TRUETOKEN: { + next(); + return context.createBoolean(true); + } + case FALSETOKEN: { + next(); + return context.createBoolean(false); + } + case DIVEQUAL: + case '/': { + /* regexp */ + const Identifier* pattern; + const Identifier* flags; + if (match(DIVEQUAL)) + failIfFalse(m_lexer->scanRegExp(pattern, flags, '=')); + else + failIfFalse(m_lexer->scanRegExp(pattern, flags)); + + int start = tokenStart(); + next(); + return context.createRegex(*pattern, *flags, start); + } + } + fail(); +} + +template <class TreeBuilder> TreeArguments JSParser::parseArguments(TreeBuilder& context) +{ + consumeOrFail('('); + if (match(')')) { + next(); + return context.createArguments(); + } + TreeExpression firstArg = parseAssignmentExpression(context); + failIfFalse(firstArg); + + TreeArgumentsList argList = context.createArgumentsList(firstArg); + TreeArgumentsList tail = argList; + while (match(',')) { + next(); + TreeExpression arg = parseAssignmentExpression(context); + failIfFalse(arg); + tail = context.createArgumentsList(tail, arg); + } + consumeOrFail(')'); + return context.createArguments(argList); +} + +template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(TreeBuilder& context) +{ + TreeExpression base = 0; + int start = tokenStart(); + int expressionStart = start; + int newCount = 0; + while (match(NEW)) { + next(); + newCount++; + } + if (match(FUNCTION)) { + const Identifier* name = &m_globalData->propertyNames->nullIdentifier; + TreeFormalParameterList parameters = 0; + TreeFunctionBody body = 0; + int openBracePos = 0; + int closeBracePos = 0; + int bodyStartLine = 0; + next(); + failIfFalse(parseFunctionInfo<FunctionNoRequirements>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)); + base = context.createFunctionExpr(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine); + } else + base = parsePrimaryExpression(context); + + failIfFalse(base); + while (true) { + switch (token().m_type) { + case '[': { + int expressionEnd = lastTokenEnd(); + next(); + int nonLHSCount = m_nonLHSCount; + int initialAssignments = m_assignmentCount; + TreeExpression property = parseExpression(context); + failIfFalse(property); + base = context.createBracketAccess(base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd()); + if (!consume(']')) + fail(); + m_nonLHSCount = nonLHSCount; + break; + } + case '(': { + if (newCount) { + newCount--; + if (match('(')) { + int exprEnd = lastTokenEnd(); + TreeArguments arguments = parseArguments(context); + failIfFalse(arguments); + base = context.createNewExpr(base, arguments, start, exprEnd, lastTokenEnd()); + } else + base = context.createNewExpr(base, start, lastTokenEnd()); + } else { + int nonLHSCount = m_nonLHSCount; + int expressionEnd = lastTokenEnd(); + TreeArguments arguments = parseArguments(context); + failIfFalse(arguments); + base = context.makeFunctionCallNode(base, arguments, expressionStart, expressionEnd, lastTokenEnd()); + m_nonLHSCount = nonLHSCount; + } + break; + } + case '.': { + int expressionEnd = lastTokenEnd(); + next(); + matchOrFail(IDENT); + base = context.createDotAccess(base, *token().m_data.ident, expressionStart, expressionEnd, tokenEnd()); + next(); + break; + } + default: + goto endMemberExpression; + } + } +endMemberExpression: + while (newCount--) + base = context.createNewExpr(base, start, lastTokenEnd()); + return base; +} + +template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeBuilder& context) +{ + AllowInOverride allowInOverride(this); + int tokenStackDepth = 0; + while (isUnaryOp(token().m_type)) { + m_nonLHSCount++; + context.appendUnaryToken(tokenStackDepth, token().m_type, tokenStart()); + next(); + } + int subExprStart = tokenStart(); + TreeExpression expr = parseMemberExpression(context); + failIfFalse(expr); + switch (token().m_type) { + case PLUSPLUS: + m_nonLHSCount++; + expr = context.makePostfixNode(expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd()); + m_assignmentCount++; + next(); + break; + case MINUSMINUS: + m_nonLHSCount++; + expr = context.makePostfixNode(expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd()); + m_assignmentCount++; + next(); + break; + } + + int end = lastTokenEnd(); + + if (!TreeBuilder::CreatesAST) + return expr; + + while (tokenStackDepth) { + switch (context.unaryTokenStackLastType(tokenStackDepth)) { + case '!': + expr = context.createLogicalNot(expr); + break; + case '~': + expr = context.makeBitwiseNotNode(expr); + break; + case '-': + expr = context.makeNegateNode(expr); + break; + case '+': + expr = context.createUnaryPlus(expr); + break; + case PLUSPLUS: + case AUTOPLUSPLUS: + expr = context.makePrefixNode(expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end); + m_assignmentCount++; + break; + case MINUSMINUS: + case AUTOMINUSMINUS: + expr = context.makePrefixNode(expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end); + m_assignmentCount++; + break; + case TYPEOF: + expr = context.makeTypeOfNode(expr); + break; + case VOIDTOKEN: + expr = context.createVoid(expr); + break; + case DELETETOKEN: + expr = context.makeDeleteNode(expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end); + break; + default: + // If we get here something has gone horribly horribly wrong + CRASH(); + } + subExprStart = context.unaryTokenStackLastStart(tokenStackDepth); + context.unaryTokenStackRemoveLast(tokenStackDepth); + } + return expr; +} + +} + +#endif + diff --git a/JavaScriptCore/parser/JSParser.h b/JavaScriptCore/parser/JSParser.h new file mode 100644 index 0000000..e212b2a --- /dev/null +++ b/JavaScriptCore/parser/JSParser.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSParser_h +#define JSParser_h +#if ENABLE(RECURSIVE_PARSE) + +namespace JSC { + +class Identifier; +class JSGlobalData; + +enum JSTokenType { + NULLTOKEN = 258, + TRUETOKEN = 259, + FALSETOKEN = 260, + BREAK = 261, + CASE = 262, + DEFAULT = 263, + FOR = 264, + NEW = 265, + VAR = 266, + CONSTTOKEN = 267, + CONTINUE = 268, + FUNCTION = 269, + RETURN = 270, + VOIDTOKEN = 271, + DELETETOKEN = 272, + IF = 273, + THISTOKEN = 274, + DO = 275, + WHILE = 276, + INTOKEN = 277, + INSTANCEOF = 278, + TYPEOF = 279, + SWITCH = 280, + WITH = 281, + RESERVED = 282, + THROW = 283, + TRY = 284, + CATCH = 285, + FINALLY = 286, + DEBUGGER = 287, + IF_WITHOUT_ELSE = 288, + ELSE = 289, + EQEQ = 290, + NE = 291, + STREQ = 292, + STRNEQ = 293, + LE = 294, + GE = 295, + OR = 296, + AND = 297, + PLUSPLUS = 298, + MINUSMINUS = 299, + LSHIFT = 300, + RSHIFT = 301, + URSHIFT = 302, + PLUSEQUAL = 303, + MINUSEQUAL = 304, + MULTEQUAL = 305, + DIVEQUAL = 306, + LSHIFTEQUAL = 307, + RSHIFTEQUAL = 308, + URSHIFTEQUAL = 309, + ANDEQUAL = 310, + MODEQUAL = 311, + XOREQUAL = 312, + OREQUAL = 313, + OPENBRACE = 314, + CLOSEBRACE = 315, + NUMBER = 316, + IDENT = 317, + STRING = 318, + AUTOPLUSPLUS = 319, + AUTOMINUSMINUS = 320 +}; + +union JSTokenData { + int intValue; + double doubleValue; + const Identifier* ident; +}; +typedef JSTokenData YYSTYPE; + +struct JSTokenInfo { + JSTokenInfo() : last_line(0) {} + int first_line; + int last_line; + int first_column; + int last_column; +}; +typedef JSTokenInfo YYLTYPE; +struct JSToken { + int m_type; + JSTokenData m_data; + JSTokenInfo m_info; +}; + +int jsParse(JSGlobalData*); +} +#endif +#endif // JSParser_h diff --git a/JavaScriptCore/parser/Lexer.cpp b/JavaScriptCore/parser/Lexer.cpp index 1af2d75..3a38273 100644 --- a/JavaScriptCore/parser/Lexer.cpp +++ b/JavaScriptCore/parser/Lexer.cpp @@ -24,7 +24,9 @@ #include "Lexer.h" #include "JSFunction.h" + #include "JSGlobalObjectFunctions.h" +#include "Identifier.h" #include "NodeInfo.h" #include "Nodes.h" #include "dtoa.h" @@ -36,10 +38,13 @@ using namespace WTF; using namespace Unicode; -// We can't specify the namespace in yacc's C output, so do it here instead. +#if ENABLE(RECURSIVE_PARSE) +#include "JSParser.h" +#else using namespace JSC; - #include "Grammar.h" +#endif + #include "Lookup.h" #include "Lexer.lut.h" @@ -872,7 +877,7 @@ doneIdentifierOrKeyword: { m_delimited = false; m_buffer16.resize(0); const HashEntry* entry = m_keywordTable.entry(m_globalData, *lvalp->ident); - token = entry ? entry->lexerValue() : IDENT; + token = entry ? entry->lexerValue() : static_cast<int>(IDENT); goto returnToken; } @@ -893,7 +898,6 @@ returnToken: { llocp->last_line = lineNumber; llocp->first_column = startOffset; llocp->last_column = currentOffset(); - m_lastToken = token; return token; } @@ -1024,20 +1028,23 @@ SourceCode Lexer::sourceCode(int openBrace, int closeBrace, int firstLine) return SourceCode(m_source->provider(), openBrace, closeBrace + 1, firstLine); const UChar* data = m_source->provider()->data(); - + ASSERT(openBrace < closeBrace); - - int numBOMsBeforeOpenBrace = 0; - int numBOMsBetweenBraces = 0; - int i; - for (i = m_source->startOffset(); i < openBrace; ++i) - numBOMsBeforeOpenBrace += data[i] == byteOrderMark; - for (; i < closeBrace; ++i) - numBOMsBetweenBraces += data[i] == byteOrderMark; + for (i = m_source->startOffset(); i < openBrace; ++i) { + if (data[i] == byteOrderMark) { + openBrace++; + closeBrace++; + } + } + for (; i < closeBrace; ++i) { + if (data[i] == byteOrderMark) + closeBrace++; + } + + ASSERT(openBrace < closeBrace); - return SourceCode(m_source->provider(), openBrace + numBOMsBeforeOpenBrace, - closeBrace + numBOMsBeforeOpenBrace + numBOMsBetweenBraces + 1, firstLine); + return SourceCode(m_source->provider(), openBrace, closeBrace + 1, firstLine); } } // namespace JSC diff --git a/JavaScriptCore/parser/Lexer.h b/JavaScriptCore/parser/Lexer.h index c76696c..f197093 100644 --- a/JavaScriptCore/parser/Lexer.h +++ b/JavaScriptCore/parser/Lexer.h @@ -49,6 +49,8 @@ namespace JSC { // Functions for the parser itself. int lex(void* lvalp, void* llocp); int lineNumber() const { return m_lineNumber; } + void setLastLineNumber(int lastLineNumber) { m_lastLineNumber = lastLineNumber; } + int lastLineNumber() const { return m_lastLineNumber; } bool prevTerminator() const { return m_terminator; } SourceCode sourceCode(int openBrace, int closeBrace, int firstLine); bool scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix = 0); @@ -84,8 +86,9 @@ namespace JSC { bool lastTokenWasRestrKeyword() const; static const size_t initialReadBufferCapacity = 32; - + int m_lineNumber; + int m_lastLineNumber; Vector<char> m_buffer8; Vector<UChar> m_buffer16; diff --git a/JavaScriptCore/parser/NodeConstructors.h b/JavaScriptCore/parser/NodeConstructors.h index dd3b981..8b64e0f 100644 --- a/JavaScriptCore/parser/NodeConstructors.h +++ b/JavaScriptCore/parser/NodeConstructors.h @@ -43,7 +43,11 @@ namespace JSC { } inline Node::Node(JSGlobalData* globalData) +#if ENABLE(RECURSIVE_PARSE) + : m_line(globalData->lexer->lastLineNumber()) +#else : m_line(globalData->lexer->lineNumber()) +#endif { } diff --git a/JavaScriptCore/parser/Parser.cpp b/JavaScriptCore/parser/Parser.cpp index 48627df..fe92b40 100644 --- a/JavaScriptCore/parser/Parser.cpp +++ b/JavaScriptCore/parser/Parser.cpp @@ -24,6 +24,7 @@ #include "Parser.h" #include "Debugger.h" +#include "JSParser.h" #include "Lexer.h" #include <wtf/HashSet.h> #include <wtf/Vector.h> @@ -58,10 +59,14 @@ void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg) Lexer& lexer = *globalData->lexer; lexer.setCode(*m_source, m_arena); - + +#if ENABLE(RECURSIVE_PARSE) + int parseError = jsParse(globalData); +#else int parseError = jscyyparse(globalData); - bool lexError = lexer.sawError(); +#endif int lineNumber = lexer.lineNumber(); + bool lexError = lexer.sawError(); lexer.clear(); if (parseError || lexError) { diff --git a/JavaScriptCore/parser/SyntaxChecker.h b/JavaScriptCore/parser/SyntaxChecker.h new file mode 100644 index 0000000..cad89f6 --- /dev/null +++ b/JavaScriptCore/parser/SyntaxChecker.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SyntaxChecker_h +#define SyntaxChecker_h + +namespace JSC { +class SyntaxChecker { +public: + SyntaxChecker(JSGlobalData*, Lexer*) + { + } + + typedef SyntaxChecker FunctionBodyBuilder; + + typedef int Expression; + typedef int SourceElements; + typedef int Arguments; + typedef int Comma; + typedef int Property; + typedef int PropertyList; + typedef int ElementList; + typedef int ArgumentsList; + typedef int FormalParameterList; + typedef int FunctionBody; + typedef int Statement; + typedef int ClauseList; + typedef int Clause; + typedef int ConstDeclList; + typedef int BinaryOperand; + + static const bool CreatesAST = false; + + int createSourceElements() { return 1; } + int makeFunctionCallNode(int, int, int, int, int) { return 1; } + void appendToComma(int, int) { } + int createCommaExpr(int, int) { return 1; } + int makeAssignNode(int, Operator, int, bool, bool, int, int, int) { return 1; } + int makePrefixNode(int, Operator, int, int, int) { return 1; } + int makePostfixNode(int, Operator, int, int, int) { return 1; } + int makeTypeOfNode(int) { return 1; } + int makeDeleteNode(int, int, int, int) { return 1; } + int makeNegateNode(int) { return 1; } + int makeBitwiseNotNode(int) { return 1; } + int createLogicalNot(int) { return 1; } + int createUnaryPlus(int) { return 1; } + int createVoid(int) { return 1; } + int thisExpr() { return 1; } + int createResolve(const Identifier*, int) { return 1; } + int createObjectLiteral() { return 1; } + int createObjectLiteral(int) { return 1; } + int createArray(int) { return 1; } + int createArray(int, int) { return 1; } + int createNumberExpr(double) { return 1; } + int createString(const Identifier*) { return 1; } + int createBoolean(bool) { return 1; } + int createNull() { return 1; } + int createBracketAccess(int, int, bool, int, int, int) { return 1; } + int createDotAccess(int, const Identifier&, int, int, int) { return 1; } + int createRegex(const Identifier&, const Identifier&, int) { return 1; } + int createNewExpr(int, int, int, int, int) { return 1; } + int createNewExpr(int, int, int) { return 1; } + int createConditionalExpr(int, int, int) { return 1; } + int createAssignResolve(const Identifier&, int, bool, int, int, int) { return 1; } + int createFunctionExpr(const Identifier*, int, int, int, int, int, int) { return 1; } + int createFunctionBody() { return 1; } + int createArguments() { return 1; } + int createArguments(int) { return 1; } + int createArgumentsList(int) { return 1; } + int createArgumentsList(int, int) { return 1; } + int createProperty(const Identifier*, int, PropertyNode::Type) { return 1; } + int createProperty(double, int, PropertyNode::Type) { return 1; } + int createPropertyList(int) { return 1; } + int createPropertyList(int, int) { return 1; } + int createElementList(int, int) { return 1; } + int createElementList(int, int, int) { return 1; } + int createFormalParameterList(const Identifier&) { return 1; } + int createFormalParameterList(int, const Identifier&) { return 1; } + int createClause(int, int) { return 1; } + int createClauseList(int) { return 1; } + int createClauseList(int, int) { return 1; } + void setUsesArguments(int) { } + int createFuncDeclStatement(const Identifier*, int, int, int, int, int, int) { return 1; } + int createBlockStatement(int, int, int) { return 1; } + int createExprStatement(int, int, int) { return 1; } + int createIfStatement(int, int, int, int) { return 1; } + int createIfStatement(int, int, int, int, int) { return 1; } + int createForLoop(int, int, int, int, bool, int, int) { return 1; } + int createForInLoop(const Identifier*, int, int, int, int, int, int, int, int, int, int) { return 1; } + int createForInLoop(int, int, int, int, int, int, int, int) { return 1; } + int createEmptyStatement() { return 1; } + int createVarStatement(int, int, int) { return 1; } + int createReturnStatement(int, int, int, int, int) { return 1; } + int createBreakStatement(int, int, int, int) { return 1; } + int createBreakStatement(const Identifier*, int, int, int, int) { return 1; } + int createContinueStatement(int, int, int, int) { return 1; } + int createContinueStatement(const Identifier*, int, int, int, int) { return 1; } + int createTryStatement(int, const Identifier*, bool, int, int, int, int) { return 1; } + int createSwitchStatement(int, int, int, int, int, int) { return 1; } + int createWhileStatement(int, int, int, int) { return 1; } + int createWithStatement(int, int, int, int, int, int) { return 1; } + int createDoWhileStatement(int, int, int, int) { return 1; } + int createLabelStatement(const Identifier*, int, int, int) { return 1; } + int createThrowStatement(int, int, int, int, int) { return 1; } + int createDebugger(int, int) { return 1; } + int createConstStatement(int, int, int) { return 1; } + int appendConstDecl(int, const Identifier*, int) { return 1; } + int createGetterOrSetterProperty(const Identifier*, const Identifier*, int, int, int, int, int, int) { return 1; } + + void appendStatement(int, int) { } + void addVar(const Identifier*, bool) { } + int combineCommaNodes(int, int) { return 1; } + int evalCount() const { return 0; } + void appendBinaryExpressionInfo(int& operandStackDepth, int, int, int, int, bool) { operandStackDepth++; } + + // Logic to handle datastructures used during parsing of binary expressions + void operatorStackPop(int& operatorStackDepth) { operatorStackDepth--; } + bool operatorStackHasHigherPrecedence(int&, int) { return true; } + BinaryOperand getFromOperandStack(int) { return 1; } + void shrinkOperandStackBy(int& operandStackDepth, int amount) { operandStackDepth -= amount; } + void appendBinaryOperation(int& operandStackDepth, int&, BinaryOperand, BinaryOperand) { operandStackDepth++; } + void operatorStackAppend(int& operatorStackDepth, int, int) { operatorStackDepth++; } + int popOperandStack(int&) { return 1; } + + void appendUnaryToken(int&, int, int) { } + int unaryTokenStackLastType(int&) { ASSERT_NOT_REACHED(); return 1; } + int unaryTokenStackLastStart(int&) { ASSERT_NOT_REACHED(); return 1; } + void unaryTokenStackRemoveLast(int&) { } + + void assignmentStackAppend(int, int, int, int, int, Operator) { } + int createAssignment(int, int, int, int, int) { ASSERT_NOT_REACHED(); return 1; } +}; + +} + +#endif diff --git a/JavaScriptCore/qt/api/qscriptengine_p.cpp b/JavaScriptCore/qt/api/qscriptengine_p.cpp index a6cf4a4..fd7978b 100644 --- a/JavaScriptCore/qt/api/qscriptengine_p.cpp +++ b/JavaScriptCore/qt/api/qscriptengine_p.cpp @@ -85,5 +85,5 @@ QScriptValuePrivate* QScriptEnginePrivate::newObject() const QScriptValuePrivate* QScriptEnginePrivate::globalObject() const { JSObjectRef globalObject = JSContextGetGlobalObject(m_context); - return new QScriptValuePrivate(this, globalObject, globalObject); + return new QScriptValuePrivate(this, globalObject); } diff --git a/JavaScriptCore/qt/api/qscriptvalue.cpp b/JavaScriptCore/qt/api/qscriptvalue.cpp index 22ff8be..8ad76a5 100644 --- a/JavaScriptCore/qt/api/qscriptvalue.cpp +++ b/JavaScriptCore/qt/api/qscriptvalue.cpp @@ -518,6 +518,34 @@ QScriptEngine* QScriptValue::engine() const } /*! + If this QScriptValue is an object, returns the internal prototype + (\c{__proto__} property) of this object; otherwise returns an + invalid QScriptValue. + + \sa setPrototype(), isObject() +*/ +QScriptValue QScriptValue::prototype() const +{ + return QScriptValuePrivate::get(d_ptr->prototype()); +} + +/*! + If this QScriptValue is an object, sets the internal prototype + (\c{__proto__} property) of this object to be \a prototype; + otherwise does nothing. + + The internal prototype should not be confused with the public + property with name "prototype"; the public prototype is usually + only set on functions that act as constructors. + + \sa prototype(), isObject() +*/ +void QScriptValue::setPrototype(const QScriptValue& prototype) +{ + d_ptr->setPrototype(QScriptValuePrivate::get(prototype)); +} + +/*! Assigns the \a other value to this QScriptValue. Note that if \a other is an object (isObject() returns true), diff --git a/JavaScriptCore/qt/api/qscriptvalue.h b/JavaScriptCore/qt/api/qscriptvalue.h index 6c42429..c82ef55 100644 --- a/JavaScriptCore/qt/api/qscriptvalue.h +++ b/JavaScriptCore/qt/api/qscriptvalue.h @@ -59,6 +59,10 @@ public: ~QScriptValue(); QScriptValue& operator=(const QScriptValue& other); + + QScriptValue prototype() const; + void setPrototype(const QScriptValue& prototype); + bool equals(const QScriptValue& other) const; bool strictlyEquals(const QScriptValue& other) const; bool instanceOf(const QScriptValue& other) const; diff --git a/JavaScriptCore/qt/api/qscriptvalue_p.h b/JavaScriptCore/qt/api/qscriptvalue_p.h index 1bb8a77..f8a1e7a 100644 --- a/JavaScriptCore/qt/api/qscriptvalue_p.h +++ b/JavaScriptCore/qt/api/qscriptvalue_p.h @@ -25,6 +25,7 @@ #include "qscriptvalue.h" #include <JavaScriptCore/JavaScript.h> #include <JavaScriptCore/JSRetainPtr.h> +#include <JSObjectRefPrivate.h> #include <QtCore/qmath.h> #include <QtCore/qnumeric.h> #include <QtCore/qshareddata.h> @@ -49,7 +50,7 @@ class QScriptValue; CNumber -> QSVP is created from int, uint, double... and no JSC engine has been bind yet. Current value is kept in m_number CBool -> QSVP is created from bool and no JSC engine has been associated yet. Current value is kept - in m_number + in m_bool CNull -> QSVP is null, but a JSC engine hasn't been associated yet. CUndefined -> QSVP is undefined, but a JSC engine hasn't been associated yet. JSValue -> QSVP is associated with engine, but there is no information about real type, the state @@ -89,7 +90,7 @@ public: inline QScriptValuePrivate(const QScriptEnginePrivate* engine, QScriptValue::SpecialValue value); inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value); - inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value, JSObjectRef object); + inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSObjectRef object); inline bool isValid() const; inline bool isBool(); @@ -108,8 +109,11 @@ public: inline qint32 toInt32() const; inline quint32 toUInt32() const; inline quint16 toUInt16() const; + inline QScriptValuePrivate* toObject(QScriptEnginePrivate* engine); inline QScriptValuePrivate* toObject(); + inline QScriptValuePrivate* prototype(); + inline void setPrototype(QScriptValuePrivate* prototype); inline bool equals(QScriptValuePrivate* other); inline bool strictlyEquals(QScriptValuePrivate* other); @@ -137,12 +141,23 @@ private: JSObject } m_state; QScriptEnginePtr m_engine; - QString m_string; - qsreal m_number; - JSValueRef m_value; - JSObjectRef m_object; - - inline void setValue(JSValueRef); + union Value + { + bool m_bool; + qsreal m_number; + JSValueRef m_value; + JSObjectRef m_object; + QString* m_string; + + Value() : m_number(0) {} + Value(bool value) : m_bool(value) {} + Value(int number) : m_number(number) {} + Value(uint number) : m_number(number) {} + Value(qsreal number) : m_number(number) {} + Value(JSValueRef value) : m_value(value) {} + Value(JSObjectRef object) : m_object(object) {} + Value(QString* string) : m_string(string) {} + } u; inline bool inherits(const char*); inline State refinedJSValue(); @@ -166,131 +181,124 @@ QScriptValue QScriptValuePrivate::get(QScriptValuePrivate* d) QScriptValuePrivate::~QScriptValuePrivate() { - if (m_value) - JSValueUnprotect(*m_engine, m_value); + if (isJSBased()) + JSValueUnprotect(*m_engine, u.m_value); + else if (isStringBased()) + delete u.m_string; } QScriptValuePrivate::QScriptValuePrivate() : m_state(Invalid) - , m_value(0) { } QScriptValuePrivate::QScriptValuePrivate(const QString& string) : m_state(CString) - , m_string(string) - , m_value(0) + , u(new QString(string)) { } QScriptValuePrivate::QScriptValuePrivate(bool value) : m_state(CBool) - , m_number(value) - , m_value(0) + , u(value) { } QScriptValuePrivate::QScriptValuePrivate(int number) : m_state(CNumber) - , m_number(number) - , m_value(0) + , u(number) { } QScriptValuePrivate::QScriptValuePrivate(uint number) : m_state(CNumber) - , m_number(number) - , m_value(0) + , u(number) { } QScriptValuePrivate::QScriptValuePrivate(qsreal number) : m_state(CNumber) - , m_number(number) - , m_value(0) + , u(number) { } QScriptValuePrivate::QScriptValuePrivate(QScriptValue::SpecialValue value) : m_state(value == QScriptValue::NullValue ? CNull : CUndefined) - , m_value(0) { } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, bool value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(engine->makeJSValue(value)) + , u(engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, int value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(m_engine->makeJSValue(value)) + , u(m_engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, uint value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(m_engine->makeJSValue(value)) + , u(m_engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, qsreal value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(m_engine->makeJSValue(value)) + , u(m_engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, const QString& value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(m_engine->makeJSValue(value)) + , u(m_engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, QScriptValue::SpecialValue value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(m_engine->makeJSValue(value)) + , u(m_engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value) : m_state(JSValue) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(value) + , u(value) { Q_ASSERT(engine); Q_ASSERT(value); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } -QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value, JSObjectRef object) +QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSObjectRef object) : m_state(JSObject) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(value) - , m_object(object) + , u(object) { Q_ASSERT(engine); - Q_ASSERT(value); Q_ASSERT(object); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, object); } bool QScriptValuePrivate::isValid() const { return m_state != Invalid; } @@ -422,11 +430,11 @@ QString QScriptValuePrivate::toString() const case Invalid: return QString(); case CBool: - return m_number ? QString::fromLatin1("true") : QString::fromLatin1("false"); + return u.m_bool ? QString::fromLatin1("true") : QString::fromLatin1("false"); case CString: - return m_string; + return *u.m_string; case CNumber: - return QScriptConverter::toString(m_number); + return QScriptConverter::toString(u.m_number); case CNull: return QString::fromLatin1("null"); case CUndefined: @@ -450,9 +458,9 @@ qsreal QScriptValuePrivate::toNumber() const case JSObject: return JSValueToNumber(*m_engine, *this, /* exception */ 0); case CNumber: - return m_number; + return u.m_number; case CBool: - return m_number ? 1 : 0; + return u.m_bool ? 1 : 0; case CNull: case Invalid: return 0; @@ -460,15 +468,15 @@ qsreal QScriptValuePrivate::toNumber() const return qQNaN(); case CString: bool ok; - qsreal result = m_string.toDouble(&ok); + qsreal result = u.m_string->toDouble(&ok); if (ok) return result; - result = m_string.toInt(&ok, 0); // Try other bases. + result = u.m_string->toInt(&ok, 0); // Try other bases. if (ok) return result; - if (m_string == "Infinity" || m_string == "-Infinity") + if (*u.m_string == "Infinity" || *u.m_string == "-Infinity") return qInf(); - return m_string.length() ? qQNaN() : 0; + return u.m_string->length() ? qQNaN() : 0; } Q_ASSERT_X(false, "toNumber()", "Not all states are included in the previous switch statement."); @@ -484,15 +492,15 @@ bool QScriptValuePrivate::toBool() const case JSObject: return true; case CNumber: - return !(qIsNaN(m_number) || !m_number); + return !(qIsNaN(u.m_number) || !u.m_number); case CBool: - return m_number; + return u.m_bool; case Invalid: case CNull: case CUndefined: return false; case CString: - return m_string.length(); + return u.m_string->length(); } Q_ASSERT_X(false, "toBool()", "Not all states are included in the previous switch statement."); @@ -551,23 +559,23 @@ QScriptValuePrivate* QScriptValuePrivate::toObject(QScriptEnginePrivate* engine) case CString: { // Exception can't occur here. - JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(m_string), /* exception */ 0); + JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(*u.m_string), /* exception */ 0); Q_ASSERT(object); - return new QScriptValuePrivate(engine, object, object); + return new QScriptValuePrivate(engine, object); } case CNumber: { // Exception can't occur here. - JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(m_number), /* exception */ 0); + JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(u.m_number), /* exception */ 0); Q_ASSERT(object); - return new QScriptValuePrivate(engine, object, object); + return new QScriptValuePrivate(engine, object); } case CBool: { // Exception can't occure here. - JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(static_cast<bool>(m_number)), /* exception */ 0); + JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(u.m_bool), /* exception */ 0); Q_ASSERT(object); - return new QScriptValuePrivate(engine, object, object); + return new QScriptValuePrivate(engine, object); } case JSValue: if (refinedJSValue() != JSPrimitive) @@ -605,6 +613,35 @@ QScriptValuePrivate* QScriptValuePrivate::toObject() return new QScriptValuePrivate; } +inline QScriptValuePrivate* QScriptValuePrivate::prototype() +{ + if (isObject()) { + JSValueRef prototype = JSObjectGetPrototype(*m_engine, *this); + if (JSValueIsNull(*m_engine, prototype)) + return new QScriptValuePrivate(engine(), prototype); + // The prototype could be either a null or a JSObject, so it is safe to cast the prototype + // to the JSObjectRef here. + return new QScriptValuePrivate(engine(), prototype, const_cast<JSObjectRef>(prototype)); + } + return new QScriptValuePrivate; +} + +inline void QScriptValuePrivate::setPrototype(QScriptValuePrivate* prototype) +{ + if (isObject() && prototype->isValid() && (prototype->isObject() || prototype->isNull())) { + if (engine() != prototype->engine()) { + qWarning("QScriptValue::setPrototype() failed: cannot set a prototype created in a different engine"); + return; + } + // FIXME: This could be replaced by a new, faster API + // look at https://bugs.webkit.org/show_bug.cgi?id=40060 + JSObjectSetPrototype(*m_engine, *this, *prototype); + JSValueRef proto = JSObjectGetPrototype(*m_engine, *this); + if (!JSValueIsStrictEqual(*m_engine, proto, *prototype)) + qWarning("QScriptValue::setPrototype() failed: cyclic prototype value"); + } +} + bool QScriptValuePrivate::equals(QScriptValuePrivate* other) { if (!isValid()) @@ -615,9 +652,9 @@ bool QScriptValuePrivate::equals(QScriptValuePrivate* other) if ((m_state == other->m_state) && !isJSBased()) { if (isNumberBased()) - return m_number == other->m_number; + return u.m_number == other->u.m_number; Q_ASSERT(isStringBased()); - return m_string == other->m_string; + return *u.m_string == *(other->u.m_string); } if (!isJSBased() && !other->isJSBased()) @@ -655,7 +692,7 @@ bool QScriptValuePrivate::strictlyEquals(QScriptValuePrivate* other) } if (isStringBased()) { if (other->isStringBased()) - return m_string == other->m_string; + return *u.m_string == *(other->u.m_string); if (other->isJSBased()) { assignEngine(other->engine()); return JSValueIsStrictEqual(*m_engine, *this, *other); @@ -663,7 +700,7 @@ bool QScriptValuePrivate::strictlyEquals(QScriptValuePrivate* other) } if (isNumberBased()) { if (other->isNumberBased()) - return m_number == other->m_number; + return u.m_number == other->u.m_number; if (other->isJSBased()) { assignEngine(other->engine()); return JSValueIsStrictEqual(*m_engine, *this, *other); @@ -690,13 +727,14 @@ bool QScriptValuePrivate::assignEngine(QScriptEnginePrivate* engine) JSValueRef value; switch (m_state) { case CBool: - value = engine->makeJSValue(static_cast<bool>(m_number)); + value = engine->makeJSValue(u.m_bool); break; case CString: - value = engine->makeJSValue(m_string); + value = engine->makeJSValue(*u.m_string); + delete u.m_string; break; case CNumber: - value = engine->makeJSValue(m_number); + value = engine->makeJSValue(u.m_number); break; case CNull: value = engine->makeJSValue(QScriptValue::NullValue); @@ -713,7 +751,8 @@ bool QScriptValuePrivate::assignEngine(QScriptEnginePrivate* engine) } m_engine = engine; m_state = JSPrimitive; - setValue(value); + u.m_value = value; + JSValueProtect(*m_engine, value); return true; } @@ -763,22 +802,15 @@ QScriptEnginePrivate* QScriptValuePrivate::engine() const QScriptValuePrivate::operator JSValueRef() const { Q_ASSERT(isJSBased()); - return m_value; + Q_ASSERT(u.m_value); + return u.m_value; } QScriptValuePrivate::operator JSObjectRef() const { Q_ASSERT(m_state == JSObject); - return m_object; -} - -void QScriptValuePrivate::setValue(JSValueRef value) -{ - if (m_value) - JSValueUnprotect(*m_engine, m_value); - if (value) - JSValueProtect(*m_engine, value); - m_value = value; + Q_ASSERT(u.m_object); + return u.m_object; } /*! @@ -806,10 +838,9 @@ QScriptValuePrivate::State QScriptValuePrivate::refinedJSValue() if (!JSValueIsObject(*m_engine, *this)) { m_state = JSPrimitive; } else { + // Difference between JSValueRef and JSObjectRef is only in their type, binarywise it is the same. + // As m_value and m_object are stored in the u union, it is enough to change the m_state only. m_state = JSObject; - // We are sure that value is an JSObject, so we can const_cast safely without - // calling JSC C API (JSValueToObject(*m_engine, *this, /* exceptions */ 0)). - m_object = const_cast<JSObjectRef>(m_value); } return m_state; } diff --git a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp index 90730c3..27d6df2 100644 --- a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp +++ b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp @@ -431,6 +431,46 @@ void tst_QScriptValue::call() QVERIFY(incr.call().isValid()); // Exception. } +void tst_QScriptValue::getSetPrototype() +{ + QScriptEngine engine; + QScriptValue object = engine.evaluate("new Object()"); + QScriptValue object2 = engine.evaluate("new Object()"); + object2.setPrototype(object); + QCOMPARE(object2.prototype().strictlyEquals(object), true); + + QScriptValue inv; + inv.setPrototype(object); + QCOMPARE(inv.prototype().isValid(), false); + + QScriptEngine otherEngine; + QScriptValue object3 = otherEngine.evaluate("new Object()"); + QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setPrototype() failed: cannot set a prototype created in a different engine"); + object2.setPrototype(object3); + QCOMPARE(object2.prototype().strictlyEquals(object), true); + + // cyclic prototypes + { + QScriptValue ret = engine.evaluate("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o"); + QCOMPARE(ret.isError(), true); + QCOMPARE(ret.toString(), QLatin1String("Error: cyclic __proto__ value")); + } + { + QScriptValue ret = engine.evaluate("p.__proto__ = { }"); + QCOMPARE(ret.isError(), false); + } + + QScriptValue old = object.prototype(); + QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setPrototype() failed: cyclic prototype value"); + object.setPrototype(object); + QCOMPARE(object.prototype().strictlyEquals(old), true); + + object2.setPrototype(object); + QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setPrototype() failed: cyclic prototype value"); + object.setPrototype(object2); + QCOMPARE(object.prototype().strictlyEquals(old), true); +} + void tst_QScriptValue::toObjectSimple() { QScriptEngine eng; diff --git a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h index 0565b6f..f9fcedb 100644 --- a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h +++ b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h @@ -47,6 +47,7 @@ private slots: void dataSharing(); void constructors_data(); void constructors(); + void getSetPrototype(); void call(); void ctor(); void toObjectSimple(); diff --git a/JavaScriptCore/runtime/ArrayPrototype.cpp b/JavaScriptCore/runtime/ArrayPrototype.cpp index 699fbe6..9407be7 100644 --- a/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -77,12 +77,14 @@ static inline bool isNumericCompareFunction(ExecState* exec, CallType callType, // If the JIT is enabled then we need to preserve the invariant that every // function with a CodeBlock also has JIT code. callData.js.functionExecutable->jitCodeForCall(exec, callData.js.scopeChain); - CodeBlock& codeBlock = callData.js.functionExecutable->generatedBytecodeForCall(); + CodeBlock* codeBlock = &callData.js.functionExecutable->generatedBytecodeForCall(); #else - CodeBlock& codeBlock = callData.js.functionExecutable->bytecodeForCall(exec, callData.js.scopeChain); + CodeBlock* codeBlock = callData.js.functionExecutable->bytecodeForCall(exec, callData.js.scopeChain); #endif + if (!codeBlock) + return false; - return codeBlock.isNumericCompareFunction(); + return codeBlock->isNumericCompareFunction(); } // ------------------------------ ArrayPrototype ---------------------------- diff --git a/JavaScriptCore/runtime/Executable.cpp b/JavaScriptCore/runtime/Executable.cpp index a18e80c..f33f3b4 100644 --- a/JavaScriptCore/runtime/Executable.cpp +++ b/JavaScriptCore/runtime/Executable.cpp @@ -119,10 +119,12 @@ JSObject* ProgramExecutable::compile(ExecState* exec, ScopeChainNode* scopeChain return 0; } -void FunctionExecutable::compileForCall(ExecState*, ScopeChainNode* scopeChainNode) +bool FunctionExecutable::compileForCall(ExecState*, ScopeChainNode* scopeChainNode) { JSGlobalData* globalData = scopeChainNode->globalData; RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source); + if (!body) + return false; if (m_forceUsesArguments) body->setUsesArguments(); body->finishParsing(m_parameters, m_name); @@ -141,12 +143,15 @@ void FunctionExecutable::compileForCall(ExecState*, ScopeChainNode* scopeChainNo m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); body->destroyData(); + return true; } -void FunctionExecutable::compileForConstruct(ExecState*, ScopeChainNode* scopeChainNode) +bool FunctionExecutable::compileForConstruct(ExecState*, ScopeChainNode* scopeChainNode) { JSGlobalData* globalData = scopeChainNode->globalData; RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source); + if (!body) + return false; if (m_forceUsesArguments) body->setUsesArguments(); body->finishParsing(m_parameters, m_name); @@ -165,6 +170,7 @@ void FunctionExecutable::compileForConstruct(ExecState*, ScopeChainNode* scopeCh m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); body->destroyData(); + return true; } #if ENABLE(JIT) @@ -193,7 +199,7 @@ void ProgramExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeCh void FunctionExecutable::generateJITCodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode) { - CodeBlock* codeBlock = &bytecodeForCall(exec, scopeChainNode); + CodeBlock* codeBlock = bytecodeForCall(exec, scopeChainNode); m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock, &m_jitCodeForCallWithArityCheck); #if !ENABLE(OPCODE_SAMPLING) @@ -204,7 +210,7 @@ void FunctionExecutable::generateJITCodeForCall(ExecState* exec, ScopeChainNode* void FunctionExecutable::generateJITCodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) { - CodeBlock* codeBlock = &bytecodeForConstruct(exec, scopeChainNode); + CodeBlock* codeBlock = bytecodeForConstruct(exec, scopeChainNode); m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, codeBlock, &m_jitCodeForConstructWithArityCheck); #if !ENABLE(OPCODE_SAMPLING) @@ -226,6 +232,8 @@ void FunctionExecutable::markAggregate(MarkStack& markStack) ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) { RefPtr<FunctionBodyNode> newFunctionBody = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source); + if (!newFunctionBody) + return 0; if (m_forceUsesArguments) newFunctionBody->setUsesArguments(); newFunctionBody->finishParsing(m_parameters, m_name); @@ -255,6 +263,8 @@ ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData ExceptionInfo* EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) { RefPtr<EvalNode> newEvalBody = globalData->parser->parse<EvalNode>(globalData, 0, 0, m_source); + if (!newEvalBody) + return 0; ScopeChain scopeChain(scopeChainNode); JSGlobalObject* globalObject = scopeChain.globalObject(); diff --git a/JavaScriptCore/runtime/Executable.h b/JavaScriptCore/runtime/Executable.h index 39ddf49..3320fe1 100644 --- a/JavaScriptCore/runtime/Executable.h +++ b/JavaScriptCore/runtime/Executable.h @@ -305,12 +305,12 @@ namespace JSC { return *m_codeBlockForConstruct; } - FunctionCodeBlock& bytecodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode) + FunctionCodeBlock* bytecodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode) { ASSERT(scopeChainNode); if (!m_codeBlockForCall) compileForCall(exec, scopeChainNode); - return *m_codeBlockForCall; + return m_codeBlockForCall; } bool isGeneratedForCall() const @@ -324,12 +324,12 @@ namespace JSC { return *m_codeBlockForCall; } - FunctionCodeBlock& bytecodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) + FunctionCodeBlock* bytecodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) { ASSERT(scopeChainNode); if (!m_codeBlockForConstruct) compileForConstruct(exec, scopeChainNode); - return *m_codeBlockForConstruct; + return m_codeBlockForConstruct; } bool isGeneratedForConstruct() const @@ -383,8 +383,8 @@ namespace JSC { m_lastLine = lastLine; } - void compileForCall(ExecState*, ScopeChainNode*); - void compileForConstruct(ExecState*, ScopeChainNode*); + bool compileForCall(ExecState*, ScopeChainNode*); + bool compileForConstruct(ExecState*, ScopeChainNode*); unsigned m_numVariables : 31; bool m_forceUsesArguments : 1; diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp index 3f24ea4..30a5ef9 100644 --- a/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/JavaScriptCore/runtime/JSGlobalData.cpp @@ -49,6 +49,7 @@ #include "Lookup.h" #include "Nodes.h" #include "Parser.h" +#include "RegExpCache.h" #include <wtf/WTFThreadData.h> #if ENABLE(JSC_MULTIPLE_THREADS) @@ -147,6 +148,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , cachedUTCOffset(NaN) , weakRandom(static_cast<int>(currentTime())) , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth) + , m_regExpCache(new RegExpCache(this)) #ifndef NDEBUG , exclusiveThread(0) #endif @@ -196,6 +198,7 @@ JSGlobalData::~JSGlobalData() deleteIdentifierTable(identifierTable); delete clientData; + delete m_regExpCache; } PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type) @@ -246,7 +249,7 @@ const Vector<Instruction>& JSGlobalData::numericCompareFunction(ExecState* exec) if (!lazyNumericCompareFunction.size() && !initializingLazyNumericCompareFunction) { initializingLazyNumericCompareFunction = true; RefPtr<FunctionExecutable> function = FunctionExecutable::fromGlobalCode(Identifier(exec, "numericCompare"), exec, 0, makeSource(UString("(function (v1, v2) { return v1 - v2; })")), 0, 0); - lazyNumericCompareFunction = function->bytecodeForCall(exec, exec->scopeChain()).instructions(); + lazyNumericCompareFunction = function->bytecodeForCall(exec, exec->scopeChain())->instructions(); initializingLazyNumericCompareFunction = false; } diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h index f48aec8..f99c8d6 100644 --- a/JavaScriptCore/runtime/JSGlobalData.h +++ b/JavaScriptCore/runtime/JSGlobalData.h @@ -44,6 +44,7 @@ #include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/RefCounted.h> +#include <wtf/ThreadSpecific.h> struct OpaqueJSClass; struct OpaqueJSClassContextData; @@ -58,6 +59,7 @@ namespace JSC { class JSObject; class Lexer; class Parser; + class RegExpCache; class Stringifier; class Structure; class UString; @@ -211,17 +213,22 @@ namespace JSC { WeakRandom weakRandom; int maxReentryDepth; + + RegExpCache* m_regExpCache; + #ifndef NDEBUG ThreadIdentifier exclusiveThread; #endif CachedTranscendentalFunction<sin> cachedSin; + WTF::ThreadSpecific<char*> stackGuards; void resetDateCache(); void startSampling(); void stopSampling(); void dumpSampleData(ExecState* exec); + RegExpCache* regExpCache() { return m_regExpCache; } private: JSGlobalData(GlobalDataType, ThreadStackType); static JSGlobalData*& sharedInstanceInternal(); diff --git a/JavaScriptCore/runtime/JSImmediate.h b/JavaScriptCore/runtime/JSImmediate.h index 9127b6a..f33d9fe 100644 --- a/JavaScriptCore/runtime/JSImmediate.h +++ b/JavaScriptCore/runtime/JSImmediate.h @@ -44,6 +44,8 @@ namespace JSC { class JSObject; class UString; + extern const size_t CELL_MASK; + #if USE(JSVALUE64) inline intptr_t reinterpretDoubleToIntptr(double value) { @@ -595,7 +597,13 @@ namespace JSC { inline bool JSValue::isCell() const { +#ifndef NDEBUG + bool r = !JSImmediate::isImmediate(asValue()); + ASSERT(!r || !(JSImmediate::rawValue(asValue()) & CELL_MASK)); + return r; +#else return !JSImmediate::isImmediate(asValue()); +#endif } inline bool JSValue::isInt32() const diff --git a/JavaScriptCore/runtime/JSString.cpp b/JavaScriptCore/runtime/JSString.cpp index 473eb77..1d5e639 100644 --- a/JavaScriptCore/runtime/JSString.cpp +++ b/JavaScriptCore/runtime/JSString.cpp @@ -150,6 +150,7 @@ JSValue JSString::replaceCharacter(ExecState* exec, UChar character, const UStri if (replacement.size()) builder.append(replacement); builder.append(UString(string).substr(matchPosition + 1)); + matchString = 0; } JSGlobalData* globalData = &exec->globalData(); diff --git a/JavaScriptCore/runtime/JSValue.cpp b/JavaScriptCore/runtime/JSValue.cpp index 728cbcf..e752d3f 100644 --- a/JavaScriptCore/runtime/JSValue.cpp +++ b/JavaScriptCore/runtime/JSValue.cpp @@ -126,10 +126,10 @@ char* JSValue::description() snprintf(description, size, "False"); else if (isNull()) snprintf(description, size, "Null"); - else { - ASSERT(isUndefined()); + else if (isUndefined()) snprintf(description, size, "Undefined"); - } + else + snprintf(description, size, "INVALID"); return description; } diff --git a/JavaScriptCore/runtime/JSZombie.cpp b/JavaScriptCore/runtime/JSZombie.cpp index 072d29b..22aabb9 100644 --- a/JavaScriptCore/runtime/JSZombie.cpp +++ b/JavaScriptCore/runtime/JSZombie.cpp @@ -37,7 +37,7 @@ Structure* JSZombie::leakedZombieStructure() { static Structure* structure = 0; if (!structure) { Structure::startIgnoringLeaks(); - structure = Structure::create(jsNull(), TypeInfo(UnspecifiedType)).releaseRef(); + structure = Structure::create(jsNull(), TypeInfo(UnspecifiedType), 0).releaseRef(); Structure::stopIgnoringLeaks(); } return structure; diff --git a/JavaScriptCore/runtime/RegExpCache.cpp b/JavaScriptCore/runtime/RegExpCache.cpp new file mode 100644 index 0000000..192df4d --- /dev/null +++ b/JavaScriptCore/runtime/RegExpCache.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 University of Szeged + * Copyright (C) 2010 Renata Hodovan (hodovan@inf.u-szeged.hu) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "RegExpCache.h" + +namespace JSC { + +PassRefPtr<RegExp> RegExpCache::lookupOrCreate(const UString& patternString, const UString& flags) +{ + if (patternString.size() < maxCacheablePatternLength) { + pair<HashMap<RegExpKey, RefPtr<RegExp> >::iterator, bool> result = m_cacheMap.add(RegExpKey(flags, patternString), 0); + if (!result.second) + return result.first->second; + } + return create(patternString, flags); +} + +PassRefPtr<RegExp> RegExpCache::create(const UString& patternString, const UString& flags) +{ + RefPtr<RegExp> regExp; + + if (!flags.isNull()) + regExp = RegExp::create(m_globalData, patternString, flags); + else + regExp = RegExp::create(m_globalData, patternString); + + if (patternString.size() >= maxCacheablePatternLength) + return regExp; + + ++m_nextKeyToEvict; + if (m_nextKeyToEvict == maxCacheableEntries) { + m_nextKeyToEvict = 0; + m_isFull = true; + } + if (m_isFull) + m_cacheMap.remove(RegExpKey(patternKeyArray[m_nextKeyToEvict].flagsValue, patternKeyArray[m_nextKeyToEvict].pattern)); + + RegExpKey key = RegExpKey(flags, patternString); + m_cacheMap.set(key, regExp); + patternKeyArray[m_nextKeyToEvict].flagsValue = key.flagsValue; + patternKeyArray[m_nextKeyToEvict].pattern = patternString.rep(); + return regExp; +} + +RegExpCache::RegExpCache(JSGlobalData* globalData) + : m_globalData(globalData) + , m_nextKeyToEvict(-1) + , m_isFull(false) +{ +} + +} diff --git a/JavaScriptCore/runtime/RegExpCache.h b/JavaScriptCore/runtime/RegExpCache.h new file mode 100644 index 0000000..03b73ac --- /dev/null +++ b/JavaScriptCore/runtime/RegExpCache.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 University of Szeged + * Copyright (C) 2010 Renata Hodovan (hodovan@inf.u-szeged.hu) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "RegExp.h" +#include "RegExpKey.h" +#include "UString.h" + +#ifndef RegExpCache_h +#define RegExpCache_h + +namespace JSC { + +class RegExpCache { +public: + PassRefPtr<RegExp> lookupOrCreate(const UString& patternString, const UString& flags); + PassRefPtr<RegExp> create(const UString& patternString, const UString& flags); + RegExpCache(JSGlobalData* globalData); + +private: + static const unsigned maxCacheablePatternLength = 256; + static const int maxCacheableEntries = 256; + + typedef HashMap<RegExpKey, RefPtr<RegExp> > RegExpCacheMap; + RegExpKey patternKeyArray[maxCacheableEntries]; + RegExpCacheMap m_cacheMap; + JSGlobalData* m_globalData; + int m_nextKeyToEvict; + bool m_isFull; +}; + +} // namespace JSC + +#endif // RegExpCache_h diff --git a/JavaScriptCore/runtime/RegExpConstructor.cpp b/JavaScriptCore/runtime/RegExpConstructor.cpp index 24476d6..166a021 100644 --- a/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -34,6 +34,7 @@ #include "RegExpObject.h" #include "RegExpPrototype.h" #include "RegExp.h" +#include "RegExpCache.h" namespace JSC { @@ -302,7 +303,7 @@ JSObject* constructRegExp(ExecState* exec, const ArgList& args) UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec); UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec); - RefPtr<RegExp> regExp = RegExp::create(&exec->globalData(), pattern, flags); + RefPtr<RegExp> regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags); if (!regExp->isValid()) return throwError(exec, createSyntaxError(exec, makeString("Invalid regular expression: ", regExp->errorMessage()))); return new (exec) RegExpObject(exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regExp.release()); diff --git a/JavaScriptCore/runtime/RegExpKey.h b/JavaScriptCore/runtime/RegExpKey.h new file mode 100644 index 0000000..e5ab438 --- /dev/null +++ b/JavaScriptCore/runtime/RegExpKey.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2010 University of Szeged + * Copyright (C) 2010 Renata Hodovan (hodovan@inf.u-szeged.hu) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "UString.h" + +#ifndef RegExpKey_h +#define RegExpKey_h + +namespace JSC { + +struct RegExpKey { + int flagsValue; + RefPtr<UString::Rep> pattern; + + RegExpKey() + : flagsValue(0) + { + } + + RegExpKey(int flags) + : flagsValue(flags) + { + } + + RegExpKey(int flags, const UString& pattern) + : flagsValue(flags) + , pattern(pattern.rep()) + { + } + + RegExpKey(int flags, const PassRefPtr<UString::Rep> pattern) + : flagsValue(flags) + , pattern(pattern) + { + } + + RegExpKey(const UString& flags, const UString& pattern) + : pattern(pattern.rep()) + { + flagsValue = getFlagsValue(flags); + } + + int getFlagsValue(const UString flags) + { + flagsValue = 0; + if (flags.find('g') != UString::NotFound) + flagsValue += 4; + if (flags.find('i') != UString::NotFound) + flagsValue += 2; + if (flags.find('m') != UString::NotFound) + flagsValue += 1; + return flagsValue; + } +}; +} // namespace JSC + +namespace WTF { +template<typename T> struct DefaultHash; +template<typename T> struct RegExpHash; + +inline bool operator==(const JSC::RegExpKey& a, const JSC::RegExpKey& b) +{ + if (a.flagsValue != b.flagsValue) + return false; + if (!a.pattern) + return !b.pattern; + if (!b.pattern) + return false; + return equal(a.pattern.get(), b.pattern.get()); +} + +template<> struct RegExpHash<JSC::RegExpKey> { + static unsigned hash(const JSC::RegExpKey& key) { return key.pattern->hash(); } + static bool equal(const JSC::RegExpKey& a, const JSC::RegExpKey& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = false; +}; + +template<> struct DefaultHash<JSC::RegExpKey> { + typedef RegExpHash<JSC::RegExpKey> Hash; +}; + +template<> struct HashTraits<JSC::RegExpKey> : GenericHashTraits<JSC::RegExpKey> { + static void constructDeletedValue(JSC::RegExpKey& slot) { slot.flagsValue = -1; } + static bool isDeletedValue(const JSC::RegExpKey& value) { return value.flagsValue == -1; } +}; +} // namespace WTF + +#endif // RegExpKey_h diff --git a/JavaScriptCore/runtime/RegExpPrototype.cpp b/JavaScriptCore/runtime/RegExpPrototype.cpp index 9d78f59..834412b 100644 --- a/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -33,6 +33,7 @@ #include "PrototypeFunction.h" #include "RegExpObject.h" #include "RegExp.h" +#include "RegExpCache.h" namespace JSC { @@ -91,7 +92,7 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) } else { UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec); UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec); - regExp = RegExp::create(&exec->globalData(), pattern, flags); + regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags); } if (!regExp->isValid()) diff --git a/JavaScriptCore/runtime/StringPrototype.cpp b/JavaScriptCore/runtime/StringPrototype.cpp index 5b90456..8b56d53 100644 --- a/JavaScriptCore/runtime/StringPrototype.cpp +++ b/JavaScriptCore/runtime/StringPrototype.cpp @@ -33,6 +33,7 @@ #include "ObjectPrototype.h" #include "Operations.h" #include "PropertyNameArray.h" +#include "RegExpCache.h" #include "RegExpConstructor.h" #include "RegExpObject.h" #include <wtf/ASCIICType.h> @@ -585,7 +586,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) * If regexp is not an object whose [[Class]] property is "RegExp", it is * replaced with the result of the expression new RegExp(regexp). */ - reg = RegExp::create(&exec->globalData(), a0.toString(exec)); + reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), UString::null()); } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int pos; @@ -636,7 +637,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) * If regexp is not an object whose [[Class]] property is "RegExp", it is * replaced with the result of the expression new RegExp(regexp). */ - reg = RegExp::create(&exec->globalData(), a0.toString(exec)); + reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), UString::null()); } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int pos; diff --git a/JavaScriptCore/runtime/SymbolTable.h b/JavaScriptCore/runtime/SymbolTable.h index f5e2669..2717075 100644 --- a/JavaScriptCore/runtime/SymbolTable.h +++ b/JavaScriptCore/runtime/SymbolTable.h @@ -121,8 +121,11 @@ namespace JSC { typedef HashMap<RefPtr<UString::Rep>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, SymbolTableIndexHashTraits> SymbolTable; - class SharedSymbolTable : public SymbolTable, public RefCounted<SharedSymbolTable> - { + class SharedSymbolTable : public SymbolTable, public RefCounted<SharedSymbolTable> { + public: + static PassRefPtr<SharedSymbolTable> create() { return adoptRef(new SharedSymbolTable); } + private: + SharedSymbolTable() { } }; } // namespace JSC diff --git a/JavaScriptCore/wtf/CMakeLists.txt b/JavaScriptCore/wtf/CMakeLists.txt index db69117..1119b3c 100644 --- a/JavaScriptCore/wtf/CMakeLists.txt +++ b/JavaScriptCore/wtf/CMakeLists.txt @@ -5,6 +5,7 @@ SET(WTF_SOURCES FastMalloc.cpp HashTable.cpp MainThread.cpp + MD5.cpp RandomNumber.cpp RefCountedLeakCounter.cpp StringExtras.cpp diff --git a/JavaScriptCore/wtf/FastMalloc.h b/JavaScriptCore/wtf/FastMalloc.h index 1ccd6a6..9729bc3 100644 --- a/JavaScriptCore/wtf/FastMalloc.h +++ b/JavaScriptCore/wtf/FastMalloc.h @@ -207,7 +207,7 @@ using WTF::fastMallocAllow; #define WTF_PRIVATE_INLINE inline #endif -#if !defined(_CRTDBG_MAP_ALLOC) && !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC) +#if !defined(_CRTDBG_MAP_ALLOC) && !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC && !PLATFORM(BREWMP)) // The nothrow functions here are actually not all that helpful, because fastMalloc will // call CRASH() rather than returning 0, and returning 0 is what nothrow is all about. diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h index 8c125c1..b92d267 100644 --- a/JavaScriptCore/wtf/Platform.h +++ b/JavaScriptCore/wtf/Platform.h @@ -100,7 +100,10 @@ #undef _WIN32 #endif - +/* COMPILER(INTEL) - Intel C++ Compiler */ +#if defined(__INTEL_COMPILER) +#define WTF_COMPILER_INTEL 1 +#endif /* ==== CPU() - the target CPU architecture ==== */ @@ -982,9 +985,12 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #define ENABLE_JIT_OPTIMIZE_MOD 1 #endif #endif -#if (CPU(X86) && USE(JSVALUE32_64)) || (CPU(X86_64) && USE(JSVALUE64)) +#if (CPU(X86) && USE(JSVALUE32_64)) || (CPU(X86_64) && USE(JSVALUE64)) \ + || CPU(ARM) +#if ENABLE(JIT) && !defined(ENABLE_JIT_OPTIMIZE_NATIVE_CALL) #define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1 #endif +#endif #if ENABLE(JIT) #ifndef ENABLE_JIT_OPTIMIZE_CALL @@ -1099,4 +1105,13 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #define ENABLE_JSC_ZOMBIES 0 +#if !defined(BUILDING_ON_TIGER) +#define ENABLE_RECURSIVE_PARSE 1 +#endif + +/* FIXME: Eventually we should enable this for all platforms and get rid of the define. */ +#if PLATFORM(MAC) +#define WTF_USE_PLATFORM_STRATEGIES 1 +#endif + #endif /* WTF_Platform_h */ diff --git a/JavaScriptCore/wtf/RetainPtr.h b/JavaScriptCore/wtf/RetainPtr.h index 77f25e0..f5a027e 100644 --- a/JavaScriptCore/wtf/RetainPtr.h +++ b/JavaScriptCore/wtf/RetainPtr.h @@ -21,6 +21,7 @@ #ifndef RetainPtr_h #define RetainPtr_h +#include "HashTraits.h" #include "TypeTraits.h" #include <algorithm> #include <CoreFoundation/CoreFoundation.h> @@ -60,6 +61,10 @@ namespace WTF { RetainPtr(const RetainPtr& o) : m_ptr(o.m_ptr) { if (PtrType ptr = m_ptr) CFRetain(ptr); } + // Hash table deleted values, which are only constructed and never copied or destroyed. + RetainPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { } + bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); } + ~RetainPtr() { if (PtrType ptr = m_ptr) CFRelease(ptr); } template <typename U> RetainPtr(const RetainPtr<U>& o) : m_ptr(o.get()) { if (PtrType ptr = m_ptr) CFRetain(ptr); } @@ -87,6 +92,8 @@ namespace WTF { void swap(RetainPtr&); private: + static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); } + PtrType m_ptr; }; @@ -193,6 +200,23 @@ namespace WTF { { return a != b.get(); } + + template<typename P> struct HashTraits<RetainPtr<P> > : GenericHashTraits<RetainPtr<P> > { + static const bool emptyValueIsZero = true; + static void constructDeletedValue(RetainPtr<P>& slot) { new (&slot) RetainPtr<P>(HashTableDeletedValue); } + static bool isDeletedValue(const RetainPtr<P>& value) { return value == reinterpret_cast<P*>(-1); } + }; + + template<typename P> struct PtrHash<RetainPtr<P> > : PtrHash<P*> { + using PtrHash<P*>::hash; + static unsigned hash(const RetainPtr<P>& key) { return hash(key.get()); } + using PtrHash<P*>::equal; + static bool equal(const RetainPtr<P>& a, const RetainPtr<P>& b) { return a == b; } + static bool equal(P* a, const RetainPtr<P>& b) { return a == b; } + static bool equal(const RetainPtr<P>& a, P* b) { return a == b; } + }; + + template<typename P> struct DefaultHash<RetainPtr<P> > { typedef PtrHash<RetainPtr<P> > Hash; }; } // namespace WTF diff --git a/JavaScriptCore/wtf/StringExtras.h b/JavaScriptCore/wtf/StringExtras.h index e8f2878..8156580 100644 --- a/JavaScriptCore/wtf/StringExtras.h +++ b/JavaScriptCore/wtf/StringExtras.h @@ -28,6 +28,7 @@ #include <stdarg.h> #include <stdio.h> +#include <string.h> #if HAVE(STRINGS_H) #include <strings.h> diff --git a/JavaScriptCore/wtf/ThreadSafeShared.h b/JavaScriptCore/wtf/ThreadSafeShared.h index 688747e..33c6612 100644 --- a/JavaScriptCore/wtf/ThreadSafeShared.h +++ b/JavaScriptCore/wtf/ThreadSafeShared.h @@ -129,16 +129,16 @@ private: template<class T> class ThreadSafeShared : public ThreadSafeSharedBase { public: - ThreadSafeShared(int initialRefCount = 1) - : ThreadSafeSharedBase(initialRefCount) - { - } - void deref() { if (derefBase()) delete static_cast<T*>(this); } + +protected: + ThreadSafeShared() + { + } }; } // namespace WTF diff --git a/JavaScriptCore/wtf/ThreadSpecific.h b/JavaScriptCore/wtf/ThreadSpecific.h index 7e5679f..893f561 100644 --- a/JavaScriptCore/wtf/ThreadSpecific.h +++ b/JavaScriptCore/wtf/ThreadSpecific.h @@ -47,13 +47,15 @@ #include <pthread.h> #elif PLATFORM(QT) #include <QThreadStorage> +#elif PLATFORM(GTK) +#include <glib.h> #elif OS(WINDOWS) #include <windows.h> #endif namespace WTF { -#if !USE(PTHREADS) && !PLATFORM(QT) && OS(WINDOWS) +#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) && OS(WINDOWS) // ThreadSpecificThreadExit should be called each time when a thread is detached. // This is done automatically for threads created with WTF::createThread. void ThreadSpecificThreadExit(); @@ -68,7 +70,7 @@ public: ~ThreadSpecific(); private: -#if !USE(PTHREADS) && !PLATFORM(QT) && OS(WINDOWS) +#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) && OS(WINDOWS) friend void ThreadSpecificThreadExit(); #endif @@ -76,7 +78,7 @@ private: void set(T*); void static destroy(void* ptr); -#if USE(PTHREADS) || PLATFORM(QT) || OS(WINDOWS) +#if USE(PTHREADS) || PLATFORM(QT) || PLATFORM(GTK) || OS(WINDOWS) struct Data : Noncopyable { Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {} #if PLATFORM(QT) @@ -85,7 +87,7 @@ private: T* value; ThreadSpecific<T>* owner; -#if !USE(PTHREADS) && !PLATFORM(QT) +#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) void (*destructor)(void*); #endif }; @@ -98,6 +100,8 @@ private: pthread_key_t m_key; #elif PLATFORM(QT) QThreadStorage<Data*> m_key; +#elif PLATFORM(GTK) + GStaticPrivate m_key; #elif OS(WINDOWS) int m_index; #endif @@ -186,6 +190,35 @@ inline void ThreadSpecific<T>::set(T* ptr) m_key.setLocalData(data); } +#elif PLATFORM(GTK) + +template<typename T> +inline ThreadSpecific<T>::ThreadSpecific() +{ + g_static_private_init(&m_key); +} + +template<typename T> +inline ThreadSpecific<T>::~ThreadSpecific() +{ + g_static_private_free(&m_key); +} + +template<typename T> +inline T* ThreadSpecific<T>::get() +{ + Data* data = static_cast<Data*>(g_static_private_get(&m_key)); + return data ? data->value : 0; +} + +template<typename T> +inline void ThreadSpecific<T>::set(T* ptr) +{ + ASSERT(!get()); + Data* data = new Data(ptr, this); + g_static_private_set(&m_key, data, destroy); +} + #elif OS(WINDOWS) // TLS_OUT_OF_INDEXES is not defined on WinCE. @@ -253,6 +286,9 @@ inline void ThreadSpecific<T>::destroy(void* ptr) // We want get() to keep working while data destructor works, because it can be called indirectly by the destructor. // Some pthreads implementations zero out the pointer before calling destroy(), so we temporarily reset it. pthread_setspecific(data->owner->m_key, ptr); +#elif PLATFORM(GTK) + // See comment as above + g_static_private_set(&data->owner->m_key, data, 0); #endif #if PLATFORM(QT) // See comment as above @@ -266,6 +302,8 @@ inline void ThreadSpecific<T>::destroy(void* ptr) pthread_setspecific(data->owner->m_key, 0); #elif PLATFORM(QT) // Do nothing here +#elif PLATFORM(GTK) + g_static_private_set(&data->owner->m_key, 0, 0); #elif OS(WINDOWS) TlsSetValue(tlsKeys()[data->owner->m_index], 0); #else @@ -285,7 +323,7 @@ inline ThreadSpecific<T>::operator T*() if (!ptr) { // Set up thread-specific value's memory pointer before invoking constructor, in case any function it calls // needs to access the value, to avoid recursion. - ptr = static_cast<T*>(fastMalloc(sizeof(T))); + ptr = static_cast<T*>(fastZeroedMalloc(sizeof(T))); set(ptr); new (ptr) T; } diff --git a/JavaScriptCore/wtf/Vector.h b/JavaScriptCore/wtf/Vector.h index b653001..c833eeb 100644 --- a/JavaScriptCore/wtf/Vector.h +++ b/JavaScriptCore/wtf/Vector.h @@ -49,7 +49,7 @@ namespace WTF { #error WTF_ALIGN macros need alignment control. #endif - #if COMPILER(GCC) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 303) + #if COMPILER(GCC) && !COMPILER(INTEL) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 303) typedef char __attribute__((__may_alias__)) AlignedBufferChar; #else typedef char AlignedBufferChar; diff --git a/JavaScriptCore/yarr/RegexCompiler.cpp b/JavaScriptCore/yarr/RegexCompiler.cpp index bcfc188..fa87186 100644 --- a/JavaScriptCore/yarr/RegexCompiler.cpp +++ b/JavaScriptCore/yarr/RegexCompiler.cpp @@ -623,7 +623,7 @@ const char* compileRegex(const UString& patternString, RegexPattern& pattern) constructor.setupOffsets(); - return false; + return 0; }; diff --git a/JavaScriptCore/yarr/RegexJIT.cpp b/JavaScriptCore/yarr/RegexJIT.cpp index 768a53d..68d3803 100644 --- a/JavaScriptCore/yarr/RegexJIT.cpp +++ b/JavaScriptCore/yarr/RegexJIT.cpp @@ -1241,16 +1241,18 @@ class RegexGenerator : private MacroAssembler { // If we get here, the alternative matched. if (m_pattern.m_body->m_callFrameSize) addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); - + ASSERT(index != returnRegister); if (m_pattern.m_body->m_hasFixedSize) { move(index, returnRegister); if (alternative->m_minimumSize) sub32(Imm32(alternative->m_minimumSize), returnRegister); + + store32(returnRegister, output); } else - pop(returnRegister); + load32(Address(output), returnRegister); + store32(index, Address(output, 4)); - store32(returnRegister, output); generateReturn(); @@ -1334,7 +1336,7 @@ class RegexGenerator : private MacroAssembler { if (!m_pattern.m_body->m_hasFixedSize) { move(index, regT0); sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); - poke(regT0, m_pattern.m_body->m_callFrameSize); + store32(regT0, Address(output)); } // Update index if necessary, and loop (without checking). @@ -1349,9 +1351,9 @@ class RegexGenerator : private MacroAssembler { if (countCheckedForCurrentAlternative - 1) { move(index, regT0); sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); - poke(regT0, m_pattern.m_body->m_callFrameSize); + store32(regT0, Address(output)); } else - poke(index, m_pattern.m_body->m_callFrameSize); + store32(index, Address(output)); } // Check if there is sufficent input to run the first alternative again. jumpIfAvailableInput(incrementForNextIter).linkTo(firstAlternativeInputChecked, this); @@ -1377,11 +1379,8 @@ class RegexGenerator : private MacroAssembler { // it has either been incremented by 1 or by (countToCheckForFirstAlternative + 1) ... // but since we're about to return a failure this doesn't really matter!) - unsigned frameSize = m_pattern.m_body->m_callFrameSize; - if (!m_pattern.m_body->m_hasFixedSize) - ++frameSize; - if (frameSize) - addPtr(Imm32(frameSize * sizeof(void*)), stackPointerRegister); + if (m_pattern.m_body->m_callFrameSize) + addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); move(Imm32(-1), returnRegister); @@ -1451,9 +1450,8 @@ public: { generateEnter(); - // TODO: do I really want this on the stack? if (!m_pattern.m_body->m_hasFixedSize) - push(index); + store32(index, Address(output)); if (m_pattern.m_body->m_callFrameSize) subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); |