diff options
Diffstat (limited to 'JavaScriptCore')
66 files changed, 2269 insertions, 381 deletions
diff --git a/JavaScriptCore/API/JSStringRef.h b/JavaScriptCore/API/JSStringRef.h index 51871b1..c5c1544 100644 --- a/JavaScriptCore/API/JSStringRef.h +++ b/JavaScriptCore/API/JSStringRef.h @@ -38,7 +38,7 @@ extern "C" { #endif #if !defined(WIN32) && !defined(_WIN32) && !defined(__WINSCW__) \ - && !((defined(__CC_ARM) || defined(__ARMCC__)) && defined(__SYMBIAN32__)) /* RVCT */ + && !((defined(__CC_ARM) || defined(__ARMCC__)) && !defined(__linux__)) /* RVCT */ /*! @typedef JSChar @abstract A Unicode character. diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index 045347a..bbdf703 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,803 @@ +2010-09-29 Patrick Gansterer <paroga@webkit.org> + + Unreviewed. + + Next try to fix cygwin build. + + * wtf/Assertions.cpp: + +2010-09-29 Patrick Gansterer <paroga@webkit.org> + + Unreviewed. + + Build fix for cygwin #2. It's OS(WINDOWS), not OS(WIN). + + * wtf/Assertions.cpp: + +2010-09-29 Patrick Gansterer <paroga@webkit.org> + + Unreviewed. + + Build fix for cygwin. + + * wtf/Assertions.cpp: + +2010-09-29 Patrick Gansterer <paroga@webkit.org> + + Reviewed by Andreas Kling. + + [WINCE] Buildfix for Assertions.cpp after r68511. + https://bugs.webkit.org/show_bug.cgi?id=46807 + + Some, but not all WinCE environments have support for IsDebuggerPresent(). + Add HAVE(ISDEBUGGERPRESENT) to make this a build option. + HAVE(ISDEBUGGERPRESENT) will be 1 for all OS(WIN) by default. + + * wtf/Assertions.cpp: + * wtf/Platform.h: + +2010-09-29 Peter Varga <pvarga@inf.u-szeged.hu> + + Reviewed by Csaba Osztrogonác. + + JSC compile fails on 32bit platform when Regexp Tracing is enabled + https://bugs.webkit.org/show_bug.cgi?id=46713 + + Fix the cast of pointer in regexp tracing to avoid the warning. + + * runtime/RegExp.cpp: + (JSC::RegExp::match): + +2010-09-28 Anders Carlsson <andersca@apple.com> + + Reviewed by Sam Weinig. + + Begin hooking up painting in the plug-in process + https://bugs.webkit.org/show_bug.cgi?id=46766 + + * JavaScriptCore.exp: + Add tryFastRealloc, used by WebKit2. + +2010-09-28 Philippe Normand <pnormand@igalia.com> + + Reviewed by Martin Robinson. + + Guard GRefPtr/GOwnPtr files with ENABLE(GLIB_SUPPORT) + https://bugs.webkit.org/show_bug.cgi?id=46721 + + Enable GOwnPtr/GRefPtr build only if glib support has been + explicitly enabled using the WTF_ENABLE_GLIB_SUPPORT macro. + + * wtf/gobject/GOwnPtr.cpp: + * wtf/gobject/GOwnPtr.h: + * wtf/gobject/GRefPtr.cpp: + * wtf/gobject/GRefPtr.h: + +2010-09-28 İsmail Dönmez <ismail@namtrac.org> + + Reviewed by Andreas Kling. + + Test for WINCE instead of WINCEBASIC, compiler always defines WINCE. + Remove reference to unexisting path JavaScriptCore/os-wince. + + * JavaScriptCore.pri: + * wtf/Assertions.cpp: + +2010-09-27 Michael Saboff <msaboff@apple.com> + + Reviewed by Geoffrey Garen. + + Changed the initialization of JSArray objects to have space for + 3 elements for the constructor that takes a ArgList argument. + This improves v8-deltablue performance by about 2.8% by reducing + the number of realloc() calls. + https://bugs.webkit.org/show_bug.cgi?id=46664 + + * runtime/JSArray.cpp: + (JSC::JSArray::JSArray): + +2010-09-27 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Darin Adler. + + Bug 46680 - Inlining string concatenation can regress interpreter performance + <rdar://problem/8362752> REGRESSION: ~6.4% sunspider regression in interpreter + Do not inline calls to string concatenation in the interpret loop. + + * interpreter/Interpreter.cpp: + (JSC::concatenateStrings): + (JSC::Interpreter::privateExecute): + +2010-09-27 Anders Carlsson <andersca@apple.com> + + Fix thinko. + + * runtime/JSCell.h: + +2010-09-27 Anders Carlsson <andersca@apple.com> + + Reviewed by Adam Roben. + + Try to fix Windows build. + + * runtime/JSCell.h: + (JSC::MSVCBugWorkaround::MSVCBugWorkaround): + (JSC::MSVCBugWorkaround::~MSVCBugWorkaround): + +2010-09-27 Erik Arvidsson <arv@chromium.org> + + Reviewed by Darin Adler. + + Add operator == for AtomicString and Vector<Uchar> + https://bugs.webkit.org/show_bug.cgi?id=46509 + + * JavaScriptCore.exp: + * wtf/text/AtomicString.cpp: + (WTF::operator==): + * wtf/text/AtomicString.h: + (WTF::operator==): + (WTF::operator!=): + +2010-09-27 Anders Carlsson <andersca@apple.com> + + Try to fix the Windows build. + + * wtf/Noncopyable.h: + +2010-09-26 Anders Carlsson <andersca@apple.com> + + Reviewed by Alexey Proskuryakov and Adam Barth. + + Add WTF_MAKE_NONCOPYABLE macro + https://bugs.webkit.org/show_bug.cgi?id=46589 + + Going forward, we'd like to get rid of the Noncopyable and FastAllocBase classes. The + reason for this is that the Itanium C++ ABI states that no empty classes of the same type + can be laid out at the same offset in the class. This can result in objects getting larger + which leads to memory regressions. (One example of this is the String class which grew by + sizeof(void*) when both its base class and its first member variable inherited indirectly + from FastAllocBase). + + * wtf/Noncopyable.h: + Add a WTF_MAKE_NONCOPYABLE macro and get rid of NoncopyableCustomAllocated. + + * runtime/JSCell.h: + * wtf/RefCounted.h: + Don't inherit from NoncopyableCustomAllocated. Instead, use WTF_MAKE_NONCOPYABLE. + +2010-09-27 Philippe Normand <pnormand@igalia.com> + + Reviewed by Martin Robinson. + + [GTK] use ENABLE(GLIB_SUPPORT) + https://bugs.webkit.org/show_bug.cgi?id=46630 + + * wtf/Platform.h: Include GTypedefs.h only if glib support + is explicitly enabled. + +2010-09-25 Holger Hans Peter Freyther <holger@moiji-mobile.com> + + Reviewed by Adam Barth. + + jsc: Document the strcat opcode. + https://bugs.webkit.org/show_bug.cgi?id=46571 + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + +2010-09-21 Holger Hans Peter Freyther <holger@moiji-mobile.com> + + Reviewed by Adam Barth. + + make-bytecode-docs.pl: Add a comment to the generated HTML + https://bugs.webkit.org/show_bug.cgi?id=46570 + + Generate an HTML Comment that this file was generated from + Interpreter.cpp with the make-bytecode-docs.pl script. + + * docs/make-bytecode-docs.pl: + +2010-09-27 Patrick Gansterer <paroga@webkit.org> + + Reviewed by Adam Barth. + + Remove WTF::stringHash functions + https://bugs.webkit.org/show_bug.cgi?id=46520 + + Since r68289 the stringHash functions are only wrappers around StringHasher::createHash. + So use StringHasher::createHash directly and remove stringHash. + + * wtf/StringHashFunctions.h: + * wtf/text/StringImpl.h: + (WTF::StringImpl::computeHash): Use WTF::StringHasher::createHash directly. + +2010-09-26 Patrick Gansterer <paroga@webkit.org> + + Reviewed by Adam Barth. + + Add WTF::StringHasher::createBlobHash + https://bugs.webkit.org/show_bug.cgi?id=46514 + + Add this function for hashing FormElementKey and QualifiedNameComponents. + + * wtf/StringHashFunctions.h: + (WTF::StringHasher::createBlobHash): + +2010-09-26 Patrick Gansterer <paroga@webkit.org> + + Reviewed by Adam Barth. + + REGRESSION (r68289): Assertion failure in StringHasher::addCharacter() (ch != invalidCharacterValue) + running websocket/tests/bad-sub-protocol-non-ascii.html + https://bugs.webkit.org/show_bug.cgi?id=46553 + + Because we use StringHasher for binary data too, so the check for invalid unicode input is wrong. + Add an additional member variable to indicate if we have an pending character + instead of only using an invalid character for this purpose. + + * wtf/StringHashFunctions.h: + (WTF::StringHasher::StringHasher): + (WTF::StringHasher::addCharacters): + (WTF::StringHasher::addCharacter): + (WTF::StringHasher::hash): + +2010-09-26 Mark Hahnenberg <mhahnenb@gmail.com> + + Reviewed by Oliver Hunt. + + valueOf called in wrong order in atan2 and date constructors. + https://bugs.webkit.org/show_bug.cgi?id=26978 + + Fixed the bug where the arguments to atan2 were being evaluated + out of order. + + * runtime/MathObject.cpp: + (JSC::mathProtoFuncATan2): + +2010-09-26 Mark Hahnenberg <mhahnenb@gmail.com> + + Reviewed by Oliver Hunt. + + valueOf called in wrong order in atan2 and date constructors. + https://bugs.webkit.org/show_bug.cgi?id=26978 + + Fixed the issue where the parameters to the Date constructor + were being evaluated to numbers more than once. + + * runtime/DateConstructor.cpp: + (JSC::constructDate): + (JSC::dateUTC): + +2010-09-25 Oliver Hunt <oliver@apple.com> + + Fix various builds + + Relearning the lesson that last minute changes are bad. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetArgumentsLength): + * jit/JITOpcodes.cpp: + (JSC::JIT::emitSlow_op_get_argument_by_val): + +2010-09-25 Oliver Hunt <oliver@apple.com> + + Reviewed by Cameron Zwarich. + + Avoid constructing arguments object when accessing length and index properties + https://bugs.webkit.org/show_bug.cgi?id=46572 + + Add opcodes to read argument length and properties, and then implement them. + Much like other lazy opcodes these opcodes take a fast path when the arguments + object has not been instantiated, and fall back on generic access mechanisms + if they are acting on an instantiated object. + + 3% win on v8-earleyboyer, no change elsewhere. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetArgumentsLength): + (JSC::BytecodeGenerator::emitGetArgumentByVal): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::BracketAccessorNode::emitBytecode): + (JSC::DotAccessorNode::emitBytecode): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_get_arguments_length): + (JSC::JIT::emitSlow_op_get_arguments_length): + (JSC::JIT::emit_op_get_argument_by_val): + (JSC::JIT::emitSlow_op_get_argument_by_val): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_get_arguments_length): + (JSC::JIT::emitSlow_op_get_arguments_length): + (JSC::JIT::emit_op_get_argument_by_val): + (JSC::JIT::emitSlow_op_get_argument_by_val): + +2010-09-25 Patrick Gansterer <paroga@webkit.org> + + Unreviewed. + + Fix typo in StringHasher class + https://bugs.webkit.org/show_bug.cgi?id=45970 + + * wtf/StringHashFunctions.h: + (WTF::StringHasher::createHash): + +2010-09-24 Patrick Gansterer <paroga@paroga.com> + + Reviewed by Gavin Barraclough. + + Add WTF::StringHasher + https://bugs.webkit.org/show_bug.cgi?id=45970 + + StringHasher is a class for calculation stringHash out of character string. + This class will unify the different usages of the same algorithm. + + * wtf/StringHashFunctions.h: + (WTF::StringHasher::StringHasher): + (WTF::StringHasher::addCharacters): + (WTF::StringHasher::addCharacter): + (WTF::StringHasher::hash): + (WTF::StringHasher::createHash): + (WTF::StringHasher::defaultCoverter): + (WTF::StringHasher::addCharactersToHash): + (WTF::stringHash): + +2010-09-24 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoffrey Garen. + + Variable declarations inside a catch scope don't get propogated to the parent scope + https://bugs.webkit.org/show_bug.cgi?id=46501 + + Add logic to make variable declaration look for a scope for the + new variable. This allows us to create a scope (eg. for catch) + and then seal it, so that additional variable declarations + contained are propogated to the correct target. Strangely this + comes out as a performance win, but I think it's mostly cache + effects. + + * parser/JSParser.cpp: + (JSC::JSParser::Scope::Scope): + (JSC::JSParser::Scope::preventNewDecls): + (JSC::JSParser::Scope::allowsNewDecls): + (JSC::JSParser::declareVariable): + (JSC::JSParser::parseVarDeclarationList): + (JSC::JSParser::parseConstDeclarationList): + (JSC::JSParser::parseTryStatement): + (JSC::JSParser::parseFormalParameters): + (JSC::JSParser::parseFunctionDeclaration): + +2010-09-24 İsmail Dönmez <ismail@namtrac.org> + + Reviewed by Csaba Osztrogonác. + + Add a Windows compatible inttypes.h header to fix WinCE build. + https://bugs.webkit.org/show_bug.cgi?id=46463 + + * os-win32/inttypes.h: Added. + +2010-09-24 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + REGRESSION(r68223): It broke 2-3 tests on bots (Requested by Ossy on #webkit). + https://bugs.webkit.org/show_bug.cgi?id=46448 + + Roll this back in, with additional logic to prevent us from delaying construction + of functions named "arguments" + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitInitLazyRegister): + (JSC::BytecodeGenerator::registerFor): + (JSC::BytecodeGenerator::createLazyRegisterIfNecessary): + (JSC::BytecodeGenerator::constRegisterFor): + (JSC::BytecodeGenerator::emitNewFunction): + (JSC::BytecodeGenerator::emitLazyNewFunction): + (JSC::BytecodeGenerator::emitNewFunctionInternal): + * bytecompiler/BytecodeGenerator.h: + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_init_lazy_reg): + (JSC::JIT::emit_op_new_func): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_init_lazy_reg): + * parser/Nodes.h: + (JSC::ScopeNode::needsActivationForMoreThanVariables): + +2010-09-23 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r68223. + http://trac.webkit.org/changeset/68223 + https://bugs.webkit.org/show_bug.cgi?id=46448 + + It broke 2-3 tests on bots (Requested by Ossy on #webkit). + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::registerFor): + (JSC::BytecodeGenerator::constRegisterFor): + (JSC::BytecodeGenerator::emitNewFunction): + * bytecompiler/BytecodeGenerator.h: + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_new_func): + (JSC::JIT::emit_op_init_arguments): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_new_func): + (JSC::JIT::emit_op_init_arguments): + * parser/Nodes.h: + +2010-09-23 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoffrey Garen. + + Delay construction of functions that aren't captured + https://bugs.webkit.org/show_bug.cgi?id=46433 + + If a function isn't captured by an activation there's no + way it can be accessed indirectly, so we can delay the + construction until it's used (similar to what we do with + arguments). We rename the existing op_init_arguments to + op_init_lazy_reg and removed its implicit handling of + the anonymous argument register, and make op_new_function + take a parameter to indicate whether it should null check + the target slot before creating the function object. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitInitLazyRegister): + (JSC::BytecodeGenerator::registerFor): + (JSC::BytecodeGenerator::createLazyRegisterIfNecessary): + (JSC::BytecodeGenerator::constRegisterFor): + (JSC::BytecodeGenerator::emitNewFunction): + (JSC::BytecodeGenerator::emitLazyNewFunction): + (JSC::BytecodeGenerator::emitNewFunctionInternal): + * bytecompiler/BytecodeGenerator.h: + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_init_lazy_reg): + (JSC::JIT::emit_op_new_func): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_init_lazy_reg): + * parser/Nodes.h: + (JSC::ScopeNode::needsActivationForMoreThanVariables): + +2010-09-23 David Kilzer <ddkilzer@apple.com> + + <rdar://problem/8460731> ~9.9% speedup when compiling interpreter with llvm-gcc-4.2 + https://bugs.webkit.org/show_bug.cgi?id=46423 + + Reviewed by Oliver Hunt. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): Disable the gcc computed + goto hacks added in r55564 when compiling with llvm-gcc-4.2. + +2010-09-23 Lucas De Marchi <lucas.demarchi@profusion.mobi> + + Reviewed by Darin Adler. + + Fix usage of enum as if it was a define + https://bugs.webkit.org/show_bug.cgi?id=46355 + + pthread.h defines PTHREAD_MUTEX_DEFAULT and PTHREAD_MUTEX_NORMAL as an + enum. Hence, it cannot be used by the preprocessor which always + evaluates that condition as true. This was giving a warning when + compiling with gcc and "-Wundef" flag. + + The second path, when PTHREAD_MUTEX_DEFAULT is not the same of + PTHREAD_MUTEX_NORMAL, is not slow. So, let's eliminate the first path + and get rid of that #if. + + * wtf/ThreadingPthreads.cpp: Always call pthread_mutexattr_init() to + set mutex type to PTHREAD_MUTEX_NORMAL. + (WTF::Mutex::Mutex): + +2010-09-23 Michael Saboff <msaboff@apple.com> + + Reviewed by Geoffrey Garen. + + Removed extraneous truncation of ovector on entry and error exit. + Changed the initialization to -1 of vector to only initialize + the start indecies, which is sufficient for the pattern/subpatterns. + Changed the JIT code to not clear the end index for subpatterns + as it isn't needed. These changes are worth ~2.7% on v8-regexp. + https://bugs.webkit.org/show_bug.cgi?id=46404 + + * runtime/RegExp.cpp: + (JSC::RegExp::match): + * yarr/RegexJIT.cpp: + (JSC::Yarr::RegexGenerator::generateParenthesesSingle): + +2010-09-22 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + Only copy captured variables into activation + https://bugs.webkit.org/show_bug.cgi?id=46330 + + We now track free variable information which means that + we no longer need to copy every variable defined in a + function. With this patch activations only retain those + variables needed for correctness. In order to interact + safely with the inspector this means that JSActivation + now provides its own lookup functions so it can avoid + trying to read or write to variables that have been + optimised out. + + * bytecode/CodeBlock.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * parser/Nodes.h: + (JSC::ScopeNode::capturedVariableCount): + (JSC::ScopeNode::captures): + * runtime/Arguments.h: + (JSC::JSActivation::copyRegisters): + * runtime/Executable.cpp: + (JSC::FunctionExecutable::FunctionExecutable): + (JSC::FunctionExecutable::compileForCallInternal): + (JSC::FunctionExecutable::compileForConstructInternal): + * runtime/Executable.h: + (JSC::FunctionExecutable::capturedVariableCount): + * runtime/JSActivation.cpp: + (JSC::JSActivation::markChildren): + (JSC::JSActivation::symbolTableGet): + (JSC::JSActivation::symbolTablePut): + (JSC::JSActivation::getOwnPropertyNames): + (JSC::JSActivation::symbolTablePutWithAttributes): + * runtime/JSActivation.h: + +2010-09-23 Ismail Donmez <ismail@namtrac.org> + + Reviewed by Andreas Kling. + + Fix jsc.exe build for Windows CE + + * jsc.pro: Add mmtimer.lib for Windows CE. + +2010-09-23 Ismail Donmez <ismail@namtrac.org> + + Unreviewed. + + JIT should be disabled on Windows CE. Broken in r64176. + + * wtf/Platform.h: + +2010-09-23 Peter Varga <pvarga@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Reduce the number of BOL checks in YARR Interpreter + https://bugs.webkit.org/show_bug.cgi?id=46260 + + Extend the YARR Interpreter with an optimization which reduces the number of + BOL assertion checks. If a "TypeBodyAlternative" byteTerm is followed by a + "TypeAssertionBOL" byteTerm it will be checked just one time. + + * yarr/RegexInterpreter.cpp: + (JSC::Yarr::Interpreter::matchDisjunction): + (JSC::Yarr::ByteCompiler::compile): + (JSC::Yarr::ByteCompiler::regexBegin): + (JSC::Yarr::ByteCompiler::alternativeBodyDisjunction): + (JSC::Yarr::ByteCompiler::emitDisjunction): + * yarr/RegexInterpreter.h: + (JSC::Yarr::ByteTerm::BodyAlternativeBegin): + (JSC::Yarr::ByteTerm::BodyAlternativeDisjunction): + (JSC::Yarr::ByteTerm::BodyAlternativeEnd): + (JSC::Yarr::ByteTerm::AlternativeBegin): + (JSC::Yarr::ByteTerm::AlternativeDisjunction): + (JSC::Yarr::ByteTerm::AlternativeEnd): + +2010-09-22 Michael Saboff <msaboff@apple.com> + + Reviewed by Gavin Barraclough. + + Fixed the cross over from alternatives executed once and + those that loop. This fixed the problem where the index + was getting messed up for looping alternatives causing an + infinite loop. + https://bugs.webkit.org/show_bug.cgi?id=46189 + + * yarr/RegexJIT.cpp: + (JSC::Yarr::RegexGenerator::generateDisjunction): + +2010-09-22 Steve Falkenburg <sfalken@apple.com> + + Rubber stamped by Jon Honeycutt. + + Allow jsc.exe to be run against unversioned ICU. + + * JavaScriptCore.vcproj/jsc/jscCommon.vsprops: + +2010-09-22 Kwang Yul Seo <skyul@company100.net> + + Reviewed by Laszlo Gombos. + + Use "typedef wchar_t JSChar" when compiled with RVCT + https://bugs.webkit.org/show_bug.cgi?id=40651 + + Use wchar_t for JSChar and UChar when compiled with RVCT. + Linux is the exception for this rule. + + * API/JSStringRef.h: + * wtf/unicode/qt4/UnicodeQt4.h: + +2010-09-22 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + [INTERPRETER] Two tests fail with SputnikError: #1.1: if argArray is neither an array nor an arguments object (see 10.1.8), a TypeError exception is thrown + https://bugs.webkit.org/show_bug.cgi?id=44245 + + Remove incorrect code from op_load_varargs in the interpreter. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + +2010-09-22 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + [JIT] fast/js/sputnik/Conformance/15_Native_Objects/15.3_Function/15.3.5/S15.3.5.3_A2_T6.html fails + https://bugs.webkit.org/show_bug.cgi?id=44246 + + JIT code generated for instanceof was not checking to ensure that the prototype property was + an object, this patch ensures that it does. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_instanceof): + (JSC::JIT::emitSlow_op_instanceof): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_instanceof): + (JSC::JIT::emitSlow_op_instanceof): + +2010-09-22 Patrick Gansterer <paroga@webkit.org> + + Reviewed by Darin Adler. + + Inline UTF8SequenceLength + https://bugs.webkit.org/show_bug.cgi?id=45589 + + * wtf/unicode/UTF8.cpp: + (WTF::Unicode::convertUTF8ToUTF16): Use inline version of UTF8SequenceLength to improve performance. + +2010-09-21 Oliver Hunt <oliver@apple.com> + + RS=Gavin Barraclough. + + Fix codeblock dumping + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * runtime/Executable.h: + (JSC::ScriptExecutable::ScriptExecutable): + +2010-09-21 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoffrey Garen. + + Speed up function.apply(..., arguments) + https://bugs.webkit.org/show_bug.cgi?id=46207 + + Add code to do argument copying inline in the case + where we're using Function.apply to forward our arguments + directly. + + * jit/JIT.cpp: + (JSC::JIT::privateCompileSlowCases): + Splitted op_load_varargs into fast and slow paths, so add the call + to the slow path generator. + * jit/JIT.h: + * jit/JITCall32_64.cpp: + Remove 32bit specific emit_op_load_varargs as the logic is the + same for all value representations + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_load_varargs): + Copy arguments inline + (JSC::JIT::emitSlow_op_load_varargs): + +2010-09-21 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + <rdar://problem/8363003> REGRESSION: ~1.4% sunspider regression in + interpreter due to 54724 and 54596 + + Fixed a typo (using "UNLIKELY" instead of "LIKELY"). + + * wtf/PassRefPtr.h: + (WTF::refIfNotNull): + (WTF::derefIfNotNull): It is likely that m_ptr != 0 because most RefPtrs + hold real data. Also, in cases where they do not hold real data, the + compiler usually sees a call to release() right before the call to the + destructor, so it can probably optimize out the test completely. + +2010-09-21 Fridrich Strba <fridrich.strba@bluewin.ch> + + Reviewed by Martin Robinson. + + Build issues with Windows versions of the GTK+ port + https://bugs.webkit.org/show_bug.cgi?id=45844 + + Link with winmm.dll when necessary and specify the executable extension + explicitely so that the Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@ + rule actually works. + + Don't try to build the ThreadSpecificWin.cpp since GTK+ port uses + a section in ThreadSpecific.cpp + + * GNUmakefile.am: + +2010-09-21 Martin Robinson <mrobinson@igalia.com> + + Reviewed by Xan Lopez. + + [GTK] 'make dist' should be fixed in preparation for the next release + https://bugs.webkit.org/show_bug.cgi?id=46129 + + * GNUmakefile.am: Update the sources list to include missing headers. + +2010-09-21 Dave Tapuska <dtapuska@rim.com> + + Reviewed by Csaba Osztrogonác. + + https://bugs.webkit.org/show_bug.cgi?id=45673 + + r65596 caused ENABLE_PROFILER_REFERENCE_OFFSET to not be + 8 byte aligned. A non 8 byte divisible value for this will + cause the sp to become non 8 byte aligned. + + Verify and correct offset values that r65596 effected that + weren't updated. + + * jit/JITStubs.cpp: + * jit/JITStubs.h: + +2010-09-21 Xan Lopez <xlopez@igalia.com> + + Reviewed by Martin Robinson. + + Fix Opcode stats compilation + https://bugs.webkit.org/show_bug.cgi?id=46079 + + The FixedArray API had changed, and <stdio.h> was not included for + printf. + + * bytecode/Opcode.cpp: + (JSC::OpcodeStats::~OpcodeStats): + 2010-09-20 Michael Saboff <msaboff@apple.com> Reviewed by Gavin Barraclough. diff --git a/JavaScriptCore/Configurations/Version.xcconfig b/JavaScriptCore/Configurations/Version.xcconfig index e82e464..f688ea8 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 = 9; +MINOR_VERSION = 10; TINY_VERSION = 0; FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION); diff --git a/JavaScriptCore/GNUmakefile.am b/JavaScriptCore/GNUmakefile.am index dd2ba21..88d1761 100644 --- a/JavaScriptCore/GNUmakefile.am +++ b/JavaScriptCore/GNUmakefile.am @@ -546,7 +546,6 @@ javascriptcore_sources += \ if TARGET_WIN32 javascriptcore_sources += \ - JavaScriptCore/wtf/ThreadSpecificWin.cpp \ JavaScriptCore/runtime/MarkStackWin.cpp else javascriptcore_sources += \ @@ -568,9 +567,9 @@ endif # USE_ICU_UNICODE # ---- if USE_GLIB_UNICODE javascriptcore_sources += \ + JavaScriptCore/wtf/unicode/UnicodeMacrosFromICU.h \ JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h \ - JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp \ - JavaScriptCore/wtf/unicode/glib/UnicodeMacrosFromICU.h + JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp endif JavaScriptCore/Lexer.lut.h: $(srcdir)/JavaScriptCore/create_hash_table $(srcdir)/JavaScriptCore/parser/Keywords.table @@ -586,7 +585,7 @@ JavaScriptCore/pcre/chartables.c: $(srcdir)/JavaScriptCore/pcre/dftables $(AM_V_GEN)$(PERL) $^ $@ bin_PROGRAMS += \ - Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@ + Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@$(EXEEXT) noinst_PROGRAMS += \ Programs/jsc \ @@ -616,6 +615,7 @@ Programs_minidom_CFLAGS = \ Programs_minidom_LDADD = \ libJavaScriptCore.la \ + $(WINMM_LIBS) \ -lm \ -lstdc++ @@ -624,8 +624,8 @@ Programs_minidom_LDFLAGS = \ -no-fast-install # jsc -Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@: Programs/jsc - $(AM_V_GEN)cp -f Programs/jsc Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@ +Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@$(EXEEXT): Programs/jsc$(EXEEXT) + $(AM_V_GEN)cp -f Programs/jsc$(EXEEXT) Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@$(EXEEXT) Programs_jsc_@WEBKITGTK_API_MAJOR_VERSION@_LDADD = Programs_jsc_@WEBKITGTK_API_MAJOR_VERSION@_SOURCES = @@ -644,7 +644,8 @@ Programs_jsc_CXXFLAGS = \ $(UNICODE_CFLAGS) Programs_jsc_LDADD = \ - libJavaScriptCore.la + libJavaScriptCore.la \ + $(WINMM_LIBS) EXTRA_DIST += \ JavaScriptCore/AUTHORS \ diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp index 13b9676..ff3d9b3 100644 --- a/JavaScriptCore/JavaScriptCore.exp +++ b/JavaScriptCore/JavaScriptCore.exp @@ -380,6 +380,7 @@ __ZN3WTF13tryFastCallocEmm __ZN3WTF13tryFastMallocEm __ZN3WTF14fastMallocSizeEPKv __ZN3WTF14numberToStringEdPt +__ZN3WTF14tryFastReallocEPvm __ZN3WTF15ThreadCondition4waitERNS_5MutexE __ZN3WTF15ThreadCondition6signalEv __ZN3WTF15ThreadCondition9broadcastEv @@ -474,6 +475,7 @@ __ZN3WTF9dayInYearEdi __ZN3WTF9emptyAtomE __ZN3WTF9xmlnsAtomE __ZN3WTFeqERKNS_12AtomicStringEPKc +__ZN3WTFeqERKNS_12AtomicStringERKNS_6VectorItLm0EEE __ZN3WTFeqERKNS_7CStringES2_ __ZN3WTFplEPKcRKNS_6StringE __ZN3WTFplERKNS_6StringEPKc diff --git a/JavaScriptCore/JavaScriptCore.pri b/JavaScriptCore/JavaScriptCore.pri index 8ef9b30..57b1ce8 100644 --- a/JavaScriptCore/JavaScriptCore.pri +++ b/JavaScriptCore/JavaScriptCore.pri @@ -56,9 +56,6 @@ DEFINES += BUILDING_QT__ BUILDING_JavaScriptCore BUILDING_WTF wince* { INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/ce-compat - DEFINES += WINCEBASIC - - INCLUDEPATH += $$PWD/../JavaScriptCore/os-wince INCLUDEPATH += $$PWD/../JavaScriptCore/os-win32 } diff --git a/JavaScriptCore/JavaScriptCore.vcproj/jsc/jscCommon.vsprops b/JavaScriptCore/JavaScriptCore.vcproj/jsc/jscCommon.vsprops index e5cc866..b63729c 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/jsc/jscCommon.vsprops +++ b/JavaScriptCore/JavaScriptCore.vcproj/jsc/jscCommon.vsprops @@ -19,7 +19,7 @@ />
<Tool
Name="VCPostBuildEventTool"
- CommandLine="if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"

mkdir 2>NUL "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt40.dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt40.dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt42.dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt42.dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\CoreFoundation.resources" xcopy /y /d /e /i "$(WebKitLibrariesDir)\bin\CoreFoundation.resources" "$(WebKitOutputDir)\bin\CoreFoundation.resources"
if exist "$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\objc$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\objc$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\ASL$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\ASL$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\libdispatch$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\libdispatch$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"

cmd /c
"
+ CommandLine="if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"

mkdir 2>NUL "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt44.dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt44.dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt44$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt44$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\libicuin$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\libicuin$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\libicuuc$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\libicuuc$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt40.dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt40.dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt42.dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt42.dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\CoreFoundation.resources" xcopy /y /d /e /i "$(WebKitLibrariesDir)\bin\CoreFoundation.resources" "$(WebKitOutputDir)\bin\CoreFoundation.resources"
if exist "$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\objc$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\objc$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\ASL$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\ASL$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\libdispatch$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\libdispatch$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"

cmd /c
"
/>
<Tool
Name="VCPreBuildEventTool"
diff --git a/JavaScriptCore/bytecode/CodeBlock.cpp b/JavaScriptCore/bytecode/CodeBlock.cpp index 0749cf6..6c0696e 100644 --- a/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/JavaScriptCore/bytecode/CodeBlock.cpp @@ -495,9 +495,9 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& printf("[%4d] create_arguments\t %s\n", location, registerName(exec, r0).data()); break; } - case op_init_arguments: { + case op_init_lazy_reg: { int r0 = (++it)->u.operand; - printf("[%4d] init_arguments\t %s\n", location, registerName(exec, r0).data()); + printf("[%4d] init_lazy_reg\t %s\n", location, registerName(exec, r0).data()); break; } case op_get_callee: { @@ -712,16 +712,16 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_resolve_global: { int r0 = (++it)->u.operand; - JSValue scope = JSValue((++it)->u.jsCell); int id0 = (++it)->u.operand; - printf("[%4d] resolve_global\t %s, %s, %s\n", location, registerName(exec, r0).data(), valueToSourceString(exec, scope).utf8().data(), idName(id0, m_identifiers[id0]).data()); + printf("[%4d] resolve_global\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); it += 2; break; } case op_resolve_global_dynamic: { int r0 = (++it)->u.operand; - JSValue scope = JSValue((++it)->u.jsCell); int id0 = (++it)->u.operand; + JSValue scope = JSValue((++it)->u.jsCell); + ++it; int depth = it[2].u.operand; printf("[%4d] resolve_global_dynamic\t %s, %s, %s, %d\n", location, registerName(exec, r0).data(), valueToSourceString(exec, scope).utf8().data(), idName(id0, m_identifiers[id0]).data(), depth); it += 3; @@ -743,16 +743,14 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_get_global_var: { int r0 = (++it)->u.operand; - JSValue scope = JSValue((++it)->u.jsCell); int index = (++it)->u.operand; - printf("[%4d] get_global_var\t %s, %s, %d\n", location, registerName(exec, r0).data(), valueToSourceString(exec, scope).utf8().data(), index); + printf("[%4d] get_global_var\t %s, %d\n", location, registerName(exec, r0).data(), index); break; } case op_put_global_var: { - JSValue scope = JSValue((++it)->u.jsCell); int index = (++it)->u.operand; int r0 = (++it)->u.operand; - printf("[%4d] put_global_var\t %s, %d, %s\n", location, valueToSourceString(exec, scope).utf8().data(), index, registerName(exec, r0).data()); + printf("[%4d] put_global_var\t %d, %s\n", location, index, registerName(exec, r0).data()); break; } case op_resolve_base: { @@ -844,6 +842,11 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& printGetByIdOp(exec, location, it, "get_string_length"); break; } + case op_get_arguments_length: { + printUnaryOp(exec, location, it, "get_arguments_length"); + it++; + break; + } case op_put_by_id: { printPutByIdOp(exec, location, it, "put_by_id"); break; @@ -892,6 +895,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); break; } + case op_get_argument_by_val: { + int r0 = (++it)->u.operand; + int r1 = (++it)->u.operand; + int r2 = (++it)->u.operand; + printf("[%4d] get_argument_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + break; + } case op_get_by_pname: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; @@ -1030,7 +1040,8 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& case op_new_func: { int r0 = (++it)->u.operand; int f0 = (++it)->u.operand; - printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(exec, r0).data(), f0); + int shouldCheck = (++it)->u.operand; + printf("[%4d] new_func\t\t %s, f%d, %s\n", location, registerName(exec, r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>"); break; } case op_new_func_exp: { diff --git a/JavaScriptCore/bytecode/CodeBlock.h b/JavaScriptCore/bytecode/CodeBlock.h index 766ad2a..cda4530 100644 --- a/JavaScriptCore/bytecode/CodeBlock.h +++ b/JavaScriptCore/bytecode/CodeBlock.h @@ -514,6 +514,7 @@ namespace JSC { int m_numCalleeRegisters; int m_numVars; + int m_numCapturedVars; int m_numParameters; bool m_isConstructor; diff --git a/JavaScriptCore/bytecode/Opcode.cpp b/JavaScriptCore/bytecode/Opcode.cpp index 8f7f01f..0bb714b 100644 --- a/JavaScriptCore/bytecode/Opcode.cpp +++ b/JavaScriptCore/bytecode/Opcode.cpp @@ -30,6 +30,11 @@ #include "config.h" #include "Opcode.h" +#if ENABLE(OPCODE_STATS) +#include <stdio.h> +#include <wtf/FixedArray.h> +#endif + using namespace std; namespace JSC { @@ -104,7 +109,7 @@ OpcodeStats::~OpcodeStats() FixedArray<int, numOpcodeIDs> sortedIndices; for (int i = 0; i < numOpcodeIDs; ++i) sortedIndices[i] = i; - qsort(sortedIndices, numOpcodeIDs, sizeof(int), compareOpcodeIndices); + qsort(sortedIndices.data(), numOpcodeIDs, sizeof(int), compareOpcodeIndices); pair<int, int> sortedPairIndices[numOpcodeIDs * numOpcodeIDs]; pair<int, int>* currentPairIndex = sortedPairIndices; diff --git a/JavaScriptCore/bytecode/Opcode.h b/JavaScriptCore/bytecode/Opcode.h index 4563ebe..03f6573 100644 --- a/JavaScriptCore/bytecode/Opcode.h +++ b/JavaScriptCore/bytecode/Opcode.h @@ -40,7 +40,7 @@ namespace JSC { #define FOR_EACH_OPCODE_ID(macro) \ macro(op_enter, 1) \ macro(op_enter_with_activation, 2) \ - macro(op_init_arguments, 2) \ + macro(op_init_lazy_reg, 2) \ macro(op_create_arguments, 2) \ macro(op_create_this, 3) \ macro(op_get_callee, 2) \ @@ -120,12 +120,14 @@ namespace JSC { macro(op_get_by_id_generic, 8) \ macro(op_get_array_length, 8) \ macro(op_get_string_length, 8) \ + macro(op_get_arguments_length, 4) \ macro(op_put_by_id, 9) \ macro(op_put_by_id_transition, 9) \ macro(op_put_by_id_replace, 9) \ macro(op_put_by_id_generic, 9) \ macro(op_del_by_id, 4) \ macro(op_get_by_val, 4) \ + macro(op_get_argument_by_val, 4) \ macro(op_get_by_pname, 7) \ macro(op_put_by_val, 4) \ macro(op_del_by_val, 4) \ @@ -153,7 +155,7 @@ namespace JSC { macro(op_switch_char, 4) \ macro(op_switch_string, 4) \ \ - macro(op_new_func, 3) \ + macro(op_new_func, 4) \ macro(op_new_func_exp, 3) \ macro(op_call, 4) \ macro(op_call_eval, 4) \ diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index ab259a6..986709b 100644 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -214,6 +214,8 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* d , m_nextGlobalIndex(-1) , m_nextConstantOffset(0) , m_globalConstantIndex(0) + , m_firstLazyFunction(0) + , m_lastLazyFunction(0) , m_globalData(&scopeChain.globalObject()->globalExec()->globalData()) , m_lastOpcodeID(op_end) #ifndef NDEBUG @@ -287,6 +289,7 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* d preserveLastVar(); } + codeBlock->m_numCapturedVars = codeBlock->m_numVars; } BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock) @@ -303,6 +306,8 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug , m_codeType(FunctionCode) , m_nextConstantOffset(0) , m_globalConstantIndex(0) + , m_firstLazyFunction(0) + , m_lastLazyFunction(0) , m_globalData(&scopeChain.globalObject()->globalExec()->globalData()) , m_lastOpcodeID(op_end) , m_emitNodeDepth(0) @@ -334,8 +339,8 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug codeBlock->setArgumentsRegister(argumentsRegister->index()); ASSERT_UNUSED(unmodifiedArgumentsRegister, unmodifiedArgumentsRegister->index() == JSC::unmodifiedArgumentsRegister(codeBlock->argumentsRegister())); - emitOpcode(op_init_arguments); - instructions().append(argumentsRegister->index()); + emitInitLazyRegister(argumentsRegister); + emitInitLazyRegister(unmodifiedArgumentsRegister); // The debugger currently retrieves the arguments object from an activation rather than pulling // it from a call frame. In the long-term it should stop doing that (<rdar://problem/6911886>), @@ -347,16 +352,54 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug } const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack(); + const DeclarationStacks::VarStack& varStack = functionBody->varStack(); + + // Captured variables and functions go first so that activations don't have + // to step over the non-captured locals to mark them. + if (functionBody->hasCapturedVariables()) { + for (size_t i = 0; i < functionStack.size(); ++i) { + FunctionBodyNode* function = functionStack[i]; + const Identifier& ident = function->ident(); + if (functionBody->captures(ident)) { + m_functions.add(ident.impl()); + emitNewFunction(addVar(ident, false), function); + } + } + for (size_t i = 0; i < varStack.size(); ++i) { + const Identifier& ident = *varStack[i].first; + if (functionBody->captures(ident)) + addVar(ident, varStack[i].second & DeclarationStacks::IsConstant); + } + } + bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables(); + codeBlock->m_numCapturedVars = codeBlock->m_numVars; + m_firstLazyFunction = codeBlock->m_numVars; for (size_t i = 0; i < functionStack.size(); ++i) { FunctionBodyNode* function = functionStack[i]; const Identifier& ident = function->ident(); - m_functions.add(ident.impl()); - emitNewFunction(addVar(ident, false), function); + if (!functionBody->captures(ident)) { + m_functions.add(ident.impl()); + RefPtr<RegisterID> reg = addVar(ident, false); + // Don't lazily create functions that override the name 'arguments' + // as this would complicate lazy instantiation of actual arguments. + if (!canLazilyCreateFunctions || ident == propertyNames().arguments) + emitNewFunction(reg.get(), function); + else { + emitInitLazyRegister(reg.get()); + m_lazyFunctions.set(reg->index(), function); + } + } } - - const DeclarationStacks::VarStack& varStack = functionBody->varStack(); - for (size_t i = 0; i < varStack.size(); ++i) - addVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant); + m_lastLazyFunction = canLazilyCreateFunctions ? codeBlock->m_numVars : m_firstLazyFunction; + for (size_t i = 0; i < varStack.size(); ++i) { + const Identifier& ident = *varStack[i].first; + if (!functionBody->captures(ident)) + addVar(ident, varStack[i].second & DeclarationStacks::IsConstant); + } + + if (debugger) + codeBlock->m_numCapturedVars = codeBlock->m_numVars; + FunctionParameters& parameters = *functionBody->parameters(); size_t parameterCount = parameters.size(); @@ -405,6 +448,8 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const Debugger* debugge , m_codeType(EvalCode) , m_nextConstantOffset(0) , m_globalConstantIndex(0) + , m_firstLazyFunction(0) + , m_lastLazyFunction(0) , m_globalData(&scopeChain.globalObject()->globalExec()->globalData()) , m_lastOpcodeID(op_end) , m_emitNodeDepth(0) @@ -430,10 +475,17 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const Debugger* debugge for (size_t i = 0; i < numVariables; ++i) variables.append(*varStack[i].first); codeBlock->adoptVariables(variables); - + codeBlock->m_numCapturedVars = codeBlock->m_numVars; preserveLastVar(); } +RegisterID* BytecodeGenerator::emitInitLazyRegister(RegisterID* reg) +{ + emitOpcode(op_init_lazy_reg); + instructions().append(reg->index()); + return reg; +} + void BytecodeGenerator::addParameter(const Identifier& ident, int parameterIndex) { // Parameters overwrite var declarations, but not function declarations. @@ -464,7 +516,7 @@ RegisterID* BytecodeGenerator::registerFor(const Identifier& ident) if (ident == propertyNames().arguments) createArgumentsIfNecessary(); - return ®isterFor(entry.getIndex()); + return createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); } bool BytecodeGenerator::willResolveToArguments(const Identifier& ident) @@ -494,6 +546,14 @@ RegisterID* BytecodeGenerator::uncheckedRegisterForArguments() return ®isterFor(entry.getIndex()); } +RegisterID* BytecodeGenerator::createLazyRegisterIfNecessary(RegisterID* reg) +{ + if (m_lastLazyFunction <= reg->index() || reg->index() < m_firstLazyFunction) + return reg; + emitLazyNewFunction(reg, m_lazyFunctions.get(reg->index())); + return reg; +} + RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident) { if (m_codeType == EvalCode) @@ -503,7 +563,7 @@ RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident) if (entry.isNull()) return 0; - return ®isterFor(entry.getIndex()); + return createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); } bool BytecodeGenerator::isLocal(const Identifier& ident) @@ -1268,6 +1328,16 @@ RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, co return dst; } +RegisterID* BytecodeGenerator::emitGetArgumentsLength(RegisterID* dst, RegisterID* base) +{ + emitOpcode(op_get_arguments_length); + instructions().append(dst->index()); + ASSERT(base->index() == m_codeBlock->argumentsRegister()); + instructions().append(base->index()); + instructions().append(addConstant(propertyNames().length)); + return dst; +} + RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value) { #if ENABLE(JIT) @@ -1335,6 +1405,16 @@ RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, return dst; } +RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property) +{ + emitOpcode(op_get_argument_by_val); + instructions().append(dst->index()); + ASSERT(base->index() == m_codeBlock->argumentsRegister()); + instructions().append(base->index()); + instructions().append(property->index()); + return dst; +} + RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property) { for (size_t i = m_forInContextStack.size(); i > 0; i--) { @@ -1411,11 +1491,23 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function) { - unsigned index = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)); + return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)), false); +} +RegisterID* BytecodeGenerator::emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* function) +{ + std::pair<FunctionOffsetMap::iterator, bool> ptr = m_functionOffsets.add(function, 0); + if (ptr.second) + ptr.first->second = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)); + return emitNewFunctionInternal(dst, ptr.first->second, true); +} + +RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, unsigned index, bool doNullCheck) +{ emitOpcode(op_new_func); instructions().append(dst->index()); instructions().append(index); + instructions().append(doNullCheck); return dst; } diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/JavaScriptCore/bytecompiler/BytecodeGenerator.h index f7bd0bf..2afa0c4 100644 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -307,6 +307,8 @@ namespace JSC { RegisterID* emitNewArray(RegisterID* dst, ElementNode*); // stops at first elision RegisterID* emitNewFunction(RegisterID* dst, FunctionBodyNode* body); + RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body); + RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index, bool shouldNullCheck); RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func); RegisterID* emitNewRegExp(RegisterID* dst, RegExp* regExp); @@ -332,10 +334,12 @@ namespace JSC { void emitMethodCheck(); RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property); + RegisterID* emitGetArgumentsLength(RegisterID* dst, RegisterID* base); RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value); RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value); RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&); RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property); + RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property); RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property); RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value); @@ -441,7 +445,7 @@ namespace JSC { typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap; RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); - + RegisterID* newRegister(); // Adds a var slot and maps it to the name ident in symbolTable(). @@ -503,6 +507,8 @@ namespace JSC { return FunctionExecutable::create(globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine()); } + RegisterID* emitInitLazyRegister(RegisterID*); + Vector<Instruction>& instructions() { return m_codeBlock->instructions(); } SymbolTable& symbolTable() { return *m_symbolTable; } @@ -512,6 +518,7 @@ namespace JSC { RegisterID* emitThrowExpressionTooDeepException(); void createArgumentsIfNecessary(); + RegisterID* createLazyRegisterIfNecessary(RegisterID*); bool m_shouldEmitDebugHooks; bool m_shouldEmitProfileHooks; @@ -551,6 +558,12 @@ namespace JSC { int m_globalVarStorageOffset; + int m_firstLazyFunction; + int m_lastLazyFunction; + HashMap<unsigned int, FunctionBodyNode*, WTF::IntHash<unsigned int>, WTF::UnsignedWithZeroKeyHashTraits<unsigned int> > m_lazyFunctions; + typedef HashMap<FunctionBodyNode*, unsigned> FunctionOffsetMap; + FunctionOffsetMap m_functionOffsets; + // Constant pool IdentifierMap m_identifierMap; JSValueMap m_jsValueMap; diff --git a/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/JavaScriptCore/bytecompiler/NodesCodegen.cpp index f098ba6..2cc1a3f 100644 --- a/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -290,6 +290,12 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { + if (m_base->isResolveNode() && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier())) { + RegisterID* property = generator.emitNode(m_subscript); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property); + } + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); RegisterID* property = generator.emitNode(m_subscript); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); @@ -300,6 +306,17 @@ RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, Regi RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { + if (m_ident == generator.propertyNames().length) { + if (!m_base->isResolveNode()) + goto nonArgumentsPath; + ResolveNode* resolveNode = static_cast<ResolveNode*>(m_base); + if (!generator.willResolveToArguments(resolveNode->identifier())) + goto nonArgumentsPath; + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedRegisterForArguments()); + } + +nonArgumentsPath: RegisterID* base = generator.emitNode(m_base); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); return generator.emitGetById(generator.finalDestination(dst), base, m_ident); diff --git a/JavaScriptCore/docs/make-bytecode-docs.pl b/JavaScriptCore/docs/make-bytecode-docs.pl index 9494d1b..5a95195 100755 --- a/JavaScriptCore/docs/make-bytecode-docs.pl +++ b/JavaScriptCore/docs/make-bytecode-docs.pl @@ -7,6 +7,7 @@ open OUTPUT, ">" . $ARGV[1]; my @undocumented = (); +print OUTPUT "<!-- Generated from Interpreter.cpp by make-bytecode-docs.pl. -->\n"; print OUTPUT "<style>p code \{ font-size: 14px; \}</style>\n"; while (<MACHINE>) { diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp index d43eb57..5943ece 100644 --- a/JavaScriptCore/interpreter/Interpreter.cpp +++ b/JavaScriptCore/interpreter/Interpreter.cpp @@ -67,6 +67,8 @@ #include "JIT.h" #endif +#define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (ENABLE(COMPUTED_GOTO_INTERPRETER) && !defined(__llvm__)) + using namespace std; namespace JSC { @@ -80,6 +82,11 @@ static int depth(CodeBlock* codeBlock, ScopeChain& sc) } #if ENABLE(INTERPRETER) +static NEVER_INLINE JSValue concatenateStrings(ExecState* exec, Register* strings, unsigned count) +{ + return jsString(exec, strings, count); +} + NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) { int dst = vPC[1].u.operand; @@ -2473,7 +2480,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi uncacheGetByID(codeBlock, vPC); NEXT_INSTRUCTION(); } -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) goto *(&&skip_id_getter_proto); #endif DEFINE_OPCODE(op_get_by_id_getter_proto) { @@ -2515,10 +2522,10 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi uncacheGetByID(codeBlock, vPC); NEXT_INSTRUCTION(); } -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) skip_id_getter_proto: #endif -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) goto *(&&skip_id_custom_proto); #endif DEFINE_OPCODE(op_get_by_id_custom_proto) { @@ -2557,7 +2564,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi uncacheGetByID(codeBlock, vPC); NEXT_INSTRUCTION(); } -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) skip_id_custom_proto: #endif DEFINE_OPCODE(op_get_by_id_self_list) { @@ -2648,7 +2655,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi uncacheGetByID(codeBlock, vPC); NEXT_INSTRUCTION(); } -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) goto *(&&skip_id_getter_self); #endif DEFINE_OPCODE(op_get_by_id_getter_self) { @@ -2688,10 +2695,10 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi uncacheGetByID(codeBlock, vPC); NEXT_INSTRUCTION(); } -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) skip_id_getter_self: #endif -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) goto *(&&skip_id_custom_self); #endif DEFINE_OPCODE(op_get_by_id_custom_self) { @@ -2725,7 +2732,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi uncacheGetByID(codeBlock, vPC); NEXT_INSTRUCTION(); } -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) skip_id_custom_self: #endif DEFINE_OPCODE(op_get_by_id_generic) { @@ -2748,7 +2755,7 @@ skip_id_custom_self: vPC += OPCODE_LENGTH(op_get_by_id_generic); NEXT_INSTRUCTION(); } -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) goto *(&&skip_id_getter_chain); #endif DEFINE_OPCODE(op_get_by_id_getter_chain) { @@ -2800,10 +2807,10 @@ skip_id_custom_self: uncacheGetByID(codeBlock, vPC); NEXT_INSTRUCTION(); } -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) skip_id_getter_chain: #endif -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) goto *(&&skip_id_custom_chain); #endif DEFINE_OPCODE(op_get_by_id_custom_chain) { @@ -2852,7 +2859,7 @@ skip_id_custom_self: uncacheGetByID(codeBlock, vPC); NEXT_INSTRUCTION(); } -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if USE(GCC_COMPUTED_GOTO_WORKAROUND) skip_id_custom_chain: #endif DEFINE_OPCODE(op_get_array_length) { @@ -3089,6 +3096,46 @@ skip_id_custom_self: vPC += OPCODE_LENGTH(op_get_by_pname); NEXT_INSTRUCTION(); } + DEFINE_OPCODE(op_get_arguments_length) { + int dst = vPC[1].u.operand; + int argumentsRegister = vPC[2].u.operand; + int property = vPC[3].u.operand; + JSValue arguments = callFrame->r(argumentsRegister).jsValue(); + if (arguments) { + Identifier& ident = codeBlock->identifier(property); + PropertySlot slot(arguments); + JSValue result = arguments.get(callFrame, ident, slot); + CHECK_FOR_EXCEPTION(); + callFrame->r(dst) = result; + } else + callFrame->r(dst) = jsNumber(callFrame, callFrame->argumentCount()); + + vPC += OPCODE_LENGTH(op_get_arguments_length); + NEXT_INSTRUCTION(); + } + DEFINE_OPCODE(op_get_argument_by_val) { + int dst = vPC[1].u.operand; + int argumentsRegister = vPC[2].u.operand; + int property = vPC[3].u.operand; + JSValue arguments = callFrame->r(argumentsRegister).jsValue(); + JSValue subscript = callFrame->r(property).jsValue(); + if (!arguments && subscript.isUInt32() && subscript.asUInt32() < callFrame->argumentCount()) { + unsigned arg = subscript.asUInt32() + 1; + unsigned numParameters = callFrame->codeBlock()->m_numParameters; + if (arg < numParameters) + callFrame->r(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters); + else + callFrame->r(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters - callFrame->argumentCount() - 1); + vPC += OPCODE_LENGTH(op_get_argument_by_val); + NEXT_INSTRUCTION(); + } + if (!arguments) { + Arguments* arguments = new (globalData) Arguments(callFrame); + callFrame->r(dst) = JSValue(arguments); + callFrame->r(unmodifiedArgumentsRegister(dst)) = JSValue(arguments); + } + // fallthrough + } DEFINE_OPCODE(op_get_by_val) { /* get_by_val dst(r) base(r) property(r) @@ -3610,8 +3657,10 @@ skip_id_custom_self: */ int dst = vPC[1].u.operand; int func = vPC[2].u.operand; + int shouldCheck = vPC[3].u.operand; - callFrame->r(dst) = JSValue(codeBlock->functionDecl(func)->make(callFrame, callFrame->scopeChain())); + if (!shouldCheck || !callFrame->r(dst).jsValue()) + callFrame->r(dst) = JSValue(codeBlock->functionDecl(func)->make(callFrame, callFrame->scopeChain())); vPC += OPCODE_LENGTH(op_new_func); NEXT_INSTRUCTION(); @@ -3832,10 +3881,8 @@ skip_id_custom_self: CHECK_FOR_EXCEPTION(); } } else { - if (!arguments.isObject()) { - exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - codeBlock->instructions().begin(), codeBlock); - goto vm_throw; - } + exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - codeBlock->instructions().begin(), codeBlock); + goto vm_throw; } } CHECK_FOR_EXCEPTION(); @@ -4137,18 +4184,17 @@ skip_id_custom_self: vPC += OPCODE_LENGTH(op_convert_this); NEXT_INSTRUCTION(); } - DEFINE_OPCODE(op_init_arguments) { - /* create_arguments dst(r) + DEFINE_OPCODE(op_init_lazy_reg) { + /* init_lazy_reg dst(r) - Initialises 'arguments' to JSValue(). + Initialises dst(r) to JSValue(). This opcode appears only at the beginning of a code block. */ int dst = vPC[1].u.operand; callFrame->r(dst) = JSValue(); - callFrame->r(unmodifiedArgumentsRegister(dst)) = JSValue(); - vPC += OPCODE_LENGTH(op_init_arguments); + vPC += OPCODE_LENGTH(op_init_lazy_reg); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_create_arguments) { @@ -4248,11 +4294,19 @@ skip_id_custom_self: goto vm_throw; } DEFINE_OPCODE(op_strcat) { + /* strcat dst(r) src(r) count(n) + + Construct a new String instance using the original + constructor, and puts the result in register dst. + The string will be the result of concatenating count + strings with values taken from registers starting at + register src. + */ int dst = vPC[1].u.operand; int src = vPC[2].u.operand; int count = vPC[3].u.operand; - callFrame->r(dst) = jsString(callFrame, &callFrame->registers()[src], count); + callFrame->r(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count); CHECK_FOR_EXCEPTION(); vPC += OPCODE_LENGTH(op_strcat); diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp index 4466fbd..a508d0c 100644 --- a/JavaScriptCore/jit/JIT.cpp +++ b/JavaScriptCore/jit/JIT.cpp @@ -225,7 +225,7 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_get_callee) DEFINE_OP(op_create_this) DEFINE_OP(op_convert_this) - DEFINE_OP(op_init_arguments) + DEFINE_OP(op_init_lazy_reg) DEFINE_OP(op_create_arguments) DEFINE_OP(op_debug) DEFINE_OP(op_del_by_id) @@ -238,7 +238,9 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_eq) DEFINE_OP(op_eq_null) DEFINE_OP(op_get_by_id) + DEFINE_OP(op_get_arguments_length) DEFINE_OP(op_get_by_val) + DEFINE_OP(op_get_argument_by_val) DEFINE_OP(op_get_by_pname) DEFINE_OP(op_get_global_var) DEFINE_OP(op_get_pnames) @@ -399,7 +401,9 @@ void JIT::privateCompileSlowCases() #endif DEFINE_SLOWCASE_OP(op_eq) DEFINE_SLOWCASE_OP(op_get_by_id) + DEFINE_SLOWCASE_OP(op_get_arguments_length) DEFINE_SLOWCASE_OP(op_get_by_val) + DEFINE_SLOWCASE_OP(op_get_argument_by_val) DEFINE_SLOWCASE_OP(op_get_by_pname) DEFINE_SLOWCASE_OP(op_instanceof) DEFINE_SLOWCASE_OP(op_jfalse) @@ -408,6 +412,7 @@ void JIT::privateCompileSlowCases() DEFINE_SLOWCASE_OP(op_jlesseq) DEFINE_SLOWCASE_OP(op_jnlesseq) DEFINE_SLOWCASE_OP(op_jtrue) + DEFINE_SLOWCASE_OP(op_load_varargs) DEFINE_SLOWCASE_OP(op_loop_if_less) DEFINE_SLOWCASE_OP(op_loop_if_lesseq) DEFINE_SLOWCASE_OP(op_loop_if_true) diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h index 6f1168b..6b2e70e 100644 --- a/JavaScriptCore/jit/JIT.h +++ b/JavaScriptCore/jit/JIT.h @@ -748,11 +748,13 @@ namespace JSC { void emit_op_eq(Instruction*); void emit_op_eq_null(Instruction*); void emit_op_get_by_id(Instruction*); + void emit_op_get_arguments_length(Instruction*); void emit_op_get_by_val(Instruction*); + void emit_op_get_argument_by_val(Instruction*); void emit_op_get_by_pname(Instruction*); void emit_op_get_global_var(Instruction*); void emit_op_get_scoped_var(Instruction*); - void emit_op_init_arguments(Instruction*); + void emit_op_init_lazy_reg(Instruction*); void emit_op_instanceof(Instruction*); void emit_op_jeq_null(Instruction*); void emit_op_jfalse(Instruction*); @@ -846,7 +848,9 @@ namespace JSC { void emitSlow_op_div(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_get_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&); + void emitSlow_op_get_arguments_length(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_get_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&); + void emitSlow_op_get_argument_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_get_by_pname(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_instanceof(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_jfalse(Instruction*, Vector<SlowCaseEntry>::iterator&); @@ -855,6 +859,7 @@ namespace JSC { void emitSlow_op_jlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&, bool invert = false); void emitSlow_op_jnlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_jtrue(Instruction*, Vector<SlowCaseEntry>::iterator&); + void emitSlow_op_load_varargs(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_loop_if_less(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_loop_if_lesseq(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_loop_if_true(Instruction*, Vector<SlowCaseEntry>::iterator&); diff --git a/JavaScriptCore/jit/JITCall32_64.cpp b/JavaScriptCore/jit/JITCall32_64.cpp index aa8e987..e4005ae 100644 --- a/JavaScriptCore/jit/JITCall32_64.cpp +++ b/JavaScriptCore/jit/JITCall32_64.cpp @@ -180,18 +180,6 @@ void JIT::emit_op_call_eval(Instruction* currentInstruction) compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++); } -void JIT::emit_op_load_varargs(Instruction* currentInstruction) -{ - int argCountDst = currentInstruction[1].u.operand; - int argsOffset = currentInstruction[2].u.operand; - - JITStubCall stubCall(this, cti_op_load_varargs); - stubCall.addArgument(Imm32(argsOffset)); - stubCall.call(); - // Stores a naked int32 in the register file. - store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register))); -} - void JIT::emit_op_call_varargs(Instruction* currentInstruction) { compileOpCallVarargs(currentInstruction); diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp index 2bfba83..c81932a 100644 --- a/JavaScriptCore/jit/JITOpcodes.cpp +++ b/JavaScriptCore/jit/JITOpcodes.cpp @@ -28,6 +28,7 @@ #if ENABLE(JIT) #include "JIT.h" +#include "Arguments.h" #include "JITInlineMethods.h" #include "JITStubCall.h" #include "JSArray.h" @@ -396,6 +397,10 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) emitJumpSlowCaseIfNotJSCell(regT0, baseVal); emitJumpSlowCaseIfNotJSCell(regT1, proto); + // Check that prototype is an object + loadPtr(Address(regT1, OBJECT_OFFSETOF(JSCell, m_structure)), regT3); + addSlowCase(branch8(NotEqual, Address(regT3, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); + // Check that baseVal 'ImplementsDefaultHasInstance'. loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); addSlowCase(branchTest8(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsDefaultHasInstance))); @@ -421,13 +426,6 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) emitPutVirtualRegister(dst); } -void JIT::emit_op_new_func(Instruction* currentInstruction) -{ - JITStubCall stubCall(this, cti_op_new_func); - stubCall.addArgument(ImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand))); - stubCall.call(currentInstruction[1].u.operand); -} - void JIT::emit_op_call(Instruction* currentInstruction) { compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++); @@ -438,18 +436,6 @@ void JIT::emit_op_call_eval(Instruction* currentInstruction) compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++); } -void JIT::emit_op_load_varargs(Instruction* currentInstruction) -{ - int argCountDst = currentInstruction[1].u.operand; - int argsOffset = currentInstruction[2].u.operand; - - JITStubCall stubCall(this, cti_op_load_varargs); - stubCall.addArgument(Imm32(argsOffset)); - stubCall.call(); - // Stores a naked int32 in the register file. - store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register))); -} - void JIT::emit_op_call_varargs(Instruction* currentInstruction) { compileOpCallVarargs(currentInstruction); @@ -1225,12 +1211,11 @@ void JIT::emit_op_create_arguments(Instruction* currentInstruction) argsCreated.link(this); } -void JIT::emit_op_init_arguments(Instruction* currentInstruction) +void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction) { unsigned dst = currentInstruction[1].u.operand; storePtr(ImmPtr(0), Address(callFrameRegister, sizeof(Register) * dst)); - storePtr(ImmPtr(0), Address(callFrameRegister, sizeof(Register) * (unmodifiedArgumentsRegister(dst)))); } void JIT::emit_op_convert_this(Instruction* currentInstruction) @@ -1447,6 +1432,7 @@ void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCas linkSlowCaseIfNotJSCell(iter, baseVal); linkSlowCaseIfNotJSCell(iter, proto); linkSlowCase(iter); + linkSlowCase(iter); JITStubCall stubCall(this, cti_op_instanceof); stubCall.addArgument(value, regT2); stubCall.addArgument(baseVal, regT2); @@ -1484,6 +1470,88 @@ void JIT::emitSlow_op_to_jsnumber(Instruction* currentInstruction, Vector<SlowCa stubCall.call(currentInstruction[1].u.operand); } +void JIT::emit_op_get_arguments_length(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + int argumentsRegister = currentInstruction[2].u.operand; + addSlowCase(branchTestPtr(NonZero, addressFor(argumentsRegister))); + emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); + sub32(Imm32(1), regT0); + emitFastArithReTagImmediate(regT0, regT0); + emitPutVirtualRegister(dst, regT0); +} + +void JIT::emitSlow_op_get_arguments_length(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + linkSlowCase(iter); + unsigned dst = currentInstruction[1].u.operand; + unsigned base = currentInstruction[2].u.operand; + Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand)); + + emitGetVirtualRegister(base, regT0); + JITStubCall stubCall(this, cti_op_get_by_id_generic); + stubCall.addArgument(regT0); + stubCall.addArgument(ImmPtr(ident)); + stubCall.call(dst); +} + +void JIT::emit_op_get_argument_by_val(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + int argumentsRegister = currentInstruction[2].u.operand; + int property = currentInstruction[3].u.operand; + addSlowCase(branchTestPtr(NonZero, addressFor(argumentsRegister))); + emitGetVirtualRegister(property, regT1); + addSlowCase(emitJumpIfNotImmediateInteger(regT1)); + add32(Imm32(1), regT1); + // regT1 now contains the integer index of the argument we want, including this + emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT2); + addSlowCase(branch32(AboveOrEqual, regT1, regT2)); + + Jump skipOutofLineParams; + int numArgs = m_codeBlock->m_numParameters; + if (numArgs) { + Jump notInInPlaceArgs = branch32(AboveOrEqual, regT1, Imm32(numArgs)); + addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT0); + loadPtr(BaseIndex(regT0, regT1, TimesEight, 0), regT0); + skipOutofLineParams = jump(); + notInInPlaceArgs.link(this); + } + + addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT0); + mul32(Imm32(sizeof(Register)), regT2, regT2); + subPtr(regT2, regT0); + loadPtr(BaseIndex(regT0, regT1, TimesEight, 0), regT0); + if (numArgs) + skipOutofLineParams.link(this); + emitPutVirtualRegister(dst, regT0); +} + +void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned arguments = currentInstruction[2].u.operand; + unsigned property = currentInstruction[3].u.operand; + + linkSlowCase(iter); + Jump skipArgumentsCreation = jump(); + + linkSlowCase(iter); + linkSlowCase(iter); + if (m_codeBlock->m_numParameters == 1) + JITStubCall(this, cti_op_create_arguments_no_params).call(); + else + JITStubCall(this, cti_op_create_arguments).call(); + emitPutVirtualRegister(arguments); + emitPutVirtualRegister(unmodifiedArgumentsRegister(arguments)); + + skipArgumentsCreation.link(this); + JITStubCall stubCall(this, cti_op_get_by_val); + stubCall.addArgument(arguments, regT2); + stubCall.addArgument(property, regT2); + stubCall.call(dst); +} + #endif // !USE(JSVALUE32_64) void JIT::emit_op_resolve_global_dynamic(Instruction* currentInstruction) @@ -1528,6 +1596,88 @@ void JIT::emit_op_new_regexp(Instruction* currentInstruction) stubCall.call(currentInstruction[1].u.operand); } +void JIT::emit_op_load_varargs(Instruction* currentInstruction) +{ + int argCountDst = currentInstruction[1].u.operand; + int argsOffset = currentInstruction[2].u.operand; + int expectedParams = m_codeBlock->m_numParameters - 1; + // Don't do inline copying if we aren't guaranteed to have a single stream + // of arguments + if (expectedParams) { + JITStubCall stubCall(this, cti_op_load_varargs); + stubCall.addArgument(Imm32(argsOffset)); + stubCall.call(); + // Stores a naked int32 in the register file. + store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register))); + return; + } + +#if USE(JSVALUE32_64) + addSlowCase(branch32(NotEqual, tagFor(argsOffset), Imm32(JSValue::EmptyValueTag))); +#else + addSlowCase(branchTestPtr(NonZero, addressFor(argsOffset))); +#endif + // Load arg count into regT0 + emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); + storePtr(regT0, addressFor(argCountDst)); + Jump endBranch = branch32(Equal, regT0, Imm32(1)); + + mul32(Imm32(sizeof(Register)), regT0, regT3); + addPtr(Imm32(static_cast<unsigned>(sizeof(Register) - RegisterFile::CallFrameHeaderSize * sizeof(Register))), callFrameRegister, regT1); + subPtr(regT3, regT1); // regT1 is now the start of the out of line arguments + addPtr(Imm32(argsOffset * sizeof(Register)), callFrameRegister, regT2); // regT2 is the target buffer + + // Bounds check the registerfile + addPtr(regT2, regT3); + addSlowCase(branchPtr(Below, AbsoluteAddress(&m_globalData->interpreter->registerFile().m_end), regT3)); + + sub32(Imm32(1), regT0); + Label loopStart = label(); + loadPtr(BaseIndex(regT1, regT0, TimesEight, static_cast<unsigned>(0 - 2 * sizeof(Register))), regT3); + storePtr(regT3, BaseIndex(regT2, regT0, TimesEight, static_cast<unsigned>(0 - sizeof(Register)))); +#if USE(JSVALUE32_64) + loadPtr(BaseIndex(regT1, regT0, TimesEight, static_cast<unsigned>(sizeof(void*) - 2 * sizeof(Register))), regT3); + storePtr(regT3, BaseIndex(regT2, regT0, TimesEight, static_cast<unsigned>(sizeof(void*) - sizeof(Register)))); +#endif + branchSubPtr(NonZero, Imm32(1), regT0).linkTo(loopStart, this); + endBranch.link(this); +} + +void JIT::emitSlow_op_load_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + int argCountDst = currentInstruction[1].u.operand; + int argsOffset = currentInstruction[2].u.operand; + int expectedParams = m_codeBlock->m_numParameters - 1; + if (expectedParams) + return; + + linkSlowCase(iter); + linkSlowCase(iter); + JITStubCall stubCall(this, cti_op_load_varargs); + stubCall.addArgument(Imm32(argsOffset)); + stubCall.call(); + // Stores a naked int32 in the register file. + store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register))); +} + +void JIT::emit_op_new_func(Instruction* currentInstruction) +{ + Jump lazyJump; + int dst = currentInstruction[1].u.operand; + if (currentInstruction[3].u.operand) { +#if USE(JSVALUE32_64) + lazyJump = branch32(NotEqual, tagFor(dst), Imm32(JSValue::EmptyValueTag)); +#else + lazyJump = branchTestPtr(NonZero, addressFor(dst)); +#endif + } + JITStubCall stubCall(this, cti_op_new_func); + stubCall.addArgument(ImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand))); + stubCall.call(currentInstruction[1].u.operand); + if (currentInstruction[3].u.operand) + lazyJump.link(this); +} + // For both JSValue32_64 and JSValue32 #if ENABLE(JIT_USE_SOFT_MODULO) #if CPU(ARM_TRADITIONAL) diff --git a/JavaScriptCore/jit/JITOpcodes32_64.cpp b/JavaScriptCore/jit/JITOpcodes32_64.cpp index 1ad19b7..ad3b558 100644 --- a/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -525,7 +525,11 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) emitJumpSlowCaseIfNotJSCell(value); emitJumpSlowCaseIfNotJSCell(baseVal); emitJumpSlowCaseIfNotJSCell(proto); - + + // Check that prototype is an object + loadPtr(Address(regT1, OBJECT_OFFSETOF(JSCell, m_structure)), regT3); + addSlowCase(branch8(NotEqual, Address(regT3, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); + // Check that baseVal 'ImplementsDefaultHasInstance'. loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); addSlowCase(branchTest8(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsDefaultHasInstance))); @@ -562,6 +566,7 @@ void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCas linkSlowCaseIfNotJSCell(iter, baseVal); linkSlowCaseIfNotJSCell(iter, proto); linkSlowCase(iter); + linkSlowCase(iter); JITStubCall stubCall(this, cti_op_instanceof); stubCall.addArgument(value); @@ -570,13 +575,6 @@ void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCas stubCall.call(dst); } -void JIT::emit_op_new_func(Instruction* currentInstruction) -{ - JITStubCall stubCall(this, cti_op_new_func); - stubCall.addArgument(ImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand))); - stubCall.call(currentInstruction[1].u.operand); -} - void JIT::emit_op_get_global_var(Instruction* currentInstruction) { int dst = currentInstruction[1].u.operand; @@ -1493,12 +1491,11 @@ void JIT::emit_op_create_arguments(Instruction* currentInstruction) argsCreated.link(this); } -void JIT::emit_op_init_arguments(Instruction* currentInstruction) +void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction) { unsigned dst = currentInstruction[1].u.operand; emitStore(dst, JSValue()); - emitStore(unmodifiedArgumentsRegister(dst), JSValue()); } void JIT::emit_op_get_callee(Instruction* currentInstruction) @@ -1565,6 +1562,89 @@ void JIT::emit_op_profile_did_call(Instruction* currentInstruction) noProfiler.link(this); } +void JIT::emit_op_get_arguments_length(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + int argumentsRegister = currentInstruction[2].u.operand; + addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), Imm32(JSValue::EmptyValueTag))); + emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); + sub32(Imm32(1), regT0); + emitStoreInt32(dst, regT0); +} + +void JIT::emitSlow_op_get_arguments_length(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + linkSlowCase(iter); + int dst = currentInstruction[1].u.operand; + int base = currentInstruction[2].u.operand; + int ident = currentInstruction[3].u.operand; + + JITStubCall stubCall(this, cti_op_get_by_id_generic); + stubCall.addArgument(base); + stubCall.addArgument(ImmPtr(&(m_codeBlock->identifier(ident)))); + stubCall.call(dst); +} + +void JIT::emit_op_get_argument_by_val(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + int argumentsRegister = currentInstruction[2].u.operand; + int property = currentInstruction[3].u.operand; + addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), Imm32(JSValue::EmptyValueTag))); + emitLoad(property, regT1, regT2); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + add32(Imm32(1), regT2); + // regT2 now contains the integer index of the argument we want, including this + emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT3); + addSlowCase(branch32(AboveOrEqual, regT2, regT3)); + + Jump skipOutofLineParams; + int numArgs = m_codeBlock->m_numParameters; + if (numArgs) { + Jump notInInPlaceArgs = branch32(AboveOrEqual, regT2, Imm32(numArgs)); + addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT1); + loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); + loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); + skipOutofLineParams = jump(); + notInInPlaceArgs.link(this); + } + + addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT1); + mul32(Imm32(sizeof(Register)), regT3, regT3); + subPtr(regT3, regT1); + loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); + loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); + if (numArgs) + skipOutofLineParams.link(this); + emitStore(dst, regT1, regT0); +} + +void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned arguments = currentInstruction[2].u.operand; + unsigned property = currentInstruction[3].u.operand; + + linkSlowCase(iter); + Jump skipArgumentsCreation = jump(); + + linkSlowCase(iter); + linkSlowCase(iter); + if (m_codeBlock->m_numParameters == 1) + JITStubCall(this, cti_op_create_arguments_no_params).call(); + else + JITStubCall(this, cti_op_create_arguments).call(); + + emitStore(arguments, regT1, regT0); + emitStore(unmodifiedArgumentsRegister(arguments), regT1, regT0); + + skipArgumentsCreation.link(this); + JITStubCall stubCall(this, cti_op_get_by_val); + stubCall.addArgument(arguments); + stubCall.addArgument(property); + stubCall.call(dst); +} + } // namespace JSC #endif // USE(JSVALUE32_64) diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp index d5e55b4..f1ec079 100644 --- a/JavaScriptCore/jit/JITStubs.cpp +++ b/JavaScriptCore/jit/JITStubs.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -234,15 +235,15 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" #elif COMPILER(GCC) && CPU(ARM_THUMB2) -#define THUNK_RETURN_ADDRESS_OFFSET 0x40 -#define PRESERVED_RETURN_ADDRESS_OFFSET 0x44 -#define PRESERVED_R4_OFFSET 0x48 -#define PRESERVED_R5_OFFSET 0x4C -#define PRESERVED_R6_OFFSET 0x50 -#define REGISTER_FILE_OFFSET 0x54 -#define CALLFRAME_OFFSET 0x58 -#define EXCEPTION_OFFSET 0x5C -#define ENABLE_PROFILER_REFERENCE_OFFSET 0x64 +#define THUNK_RETURN_ADDRESS_OFFSET 0x38 +#define PRESERVED_RETURN_ADDRESS_OFFSET 0x3C +#define PRESERVED_R4_OFFSET 0x40 +#define PRESERVED_R5_OFFSET 0x44 +#define PRESERVED_R6_OFFSET 0x48 +#define REGISTER_FILE_OFFSET 0x4C +#define CALLFRAME_OFFSET 0x50 +#define EXCEPTION_OFFSET 0x54 +#define ENABLE_PROFILER_REFERENCE_OFFSET 0x58 #elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL) @@ -467,14 +468,14 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" #elif COMPILER(GCC) && CPU(ARM_THUMB2) -#define THUNK_RETURN_ADDRESS_OFFSET 0x1C -#define PRESERVED_RETURN_ADDRESS_OFFSET 0x20 -#define PRESERVED_R4_OFFSET 0x24 -#define PRESERVED_R5_OFFSET 0x28 -#define PRESERVED_R6_OFFSET 0x2C -#define REGISTER_FILE_OFFSET 0x30 -#define CALLFRAME_OFFSET 0x34 -#define EXCEPTION_OFFSET 0x38 +#define THUNK_RETURN_ADDRESS_OFFSET 0x20 +#define PRESERVED_RETURN_ADDRESS_OFFSET 0x24 +#define PRESERVED_R4_OFFSET 0x28 +#define PRESERVED_R5_OFFSET 0x2C +#define PRESERVED_R6_OFFSET 0x30 +#define REGISTER_FILE_OFFSET 0x34 +#define CALLFRAME_OFFSET 0x38 +#define EXCEPTION_OFFSET 0x3C #define ENABLE_PROFILER_REFERENCE_OFFSET 0x40 #elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL) diff --git a/JavaScriptCore/jit/JITStubs.h b/JavaScriptCore/jit/JITStubs.h index d3d7c53..2b22e6d 100644 --- a/JavaScriptCore/jit/JITStubs.h +++ b/JavaScriptCore/jit/JITStubs.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -146,8 +147,8 @@ namespace JSC { struct JITStackFrame { JITStubArg reserved; // Unused JITStubArg args[6]; -#if USE(JSVALUE32_64) - void* padding[2]; // Maintain 16-byte stack alignment. +#if !USE(JSVALUE32_64) + void* padding; // Maintain 16-byte stack alignment. #endif ReturnAddressPtr thunkReturnAddress; @@ -162,8 +163,6 @@ namespace JSC { CallFrame* callFrame; JSValue* exception; - void* padding2; - // These arguments passed on the stack. Profiler** enabledProfilerReference; JSGlobalData* globalData; diff --git a/JavaScriptCore/jsc.pro b/JavaScriptCore/jsc.pro index 6f3831e..670ca61 100644 --- a/JavaScriptCore/jsc.pro +++ b/JavaScriptCore/jsc.pro @@ -32,6 +32,10 @@ mac { LIBS_PRIVATE += -framework AppKit } +wince* { + LIBS += mmtimer.lib +} + # Prevent warnings about difference in visibility on Mac OS X contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols unix:contains(QT_CONFIG, reduce_relocations):CONFIG += bsymbolic_functions diff --git a/JavaScriptCore/os-win32/inttypes.h b/JavaScriptCore/os-win32/inttypes.h new file mode 100644 index 0000000..0ed6718 --- /dev/null +++ b/JavaScriptCore/os-win32/inttypes.h @@ -0,0 +1,261 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006 Alexander Chemeris +// +// 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. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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 INTTYPES_WIN32_H +#define INTTYPES_WIN32_H + +#include <wtf/Platform.h> + +#if !COMPILER(MSVC) +#error "This inttypes.h file should only be compiled with MSVC" +#endif + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif + +#endif + +#endif diff --git a/JavaScriptCore/parser/JSParser.cpp b/JavaScriptCore/parser/JSParser.cpp index 540dc3b..0e526ac 100644 --- a/JavaScriptCore/parser/JSParser.cpp +++ b/JavaScriptCore/parser/JSParser.cpp @@ -204,6 +204,7 @@ private: Scope() : m_usesEval(false) , m_needsFullActivation(false) + , m_allowsNewDecls(true) { } @@ -212,6 +213,9 @@ private: m_declaredVariables.add(ident->ustring().impl()); } + void preventNewDecls() { m_allowsNewDecls = false; } + bool allowsNewDecls() const { return m_allowsNewDecls; } + void useVariable(const Identifier* ident, bool isEval) { m_usesEval |= isEval; @@ -249,6 +253,7 @@ private: private: bool m_usesEval; bool m_needsFullActivation; + bool m_allowsNewDecls; IdentifierSet m_declaredVariables; IdentifierSet m_usedVariables; IdentifierSet m_closedVariables; @@ -287,6 +292,17 @@ private: m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables); m_scopeStack.removeLast(); } + + void declareVariable(const Identifier* ident) + { + unsigned i = m_scopeStack.size() - 1; + ASSERT(i < m_scopeStack.size()); + while (!m_scopeStack[i].allowsNewDecls()) { + i--; + ASSERT(i < m_scopeStack.size()); + } + m_scopeStack[i].declareVariable(ident); + } ScopeStack m_scopeStack; }; @@ -425,7 +441,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(Tr lastIdent = name; next(); bool hasInitializer = match(EQUAL); - currentScope()->declareVariable(name); + declareVariable(name); context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0); if (hasInitializer) { int varDivot = tokenStart() + 1; @@ -457,7 +473,7 @@ template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationLi const Identifier* name = m_token.m_data.ident; next(); bool hasInitializer = match(EQUAL); - currentScope()->declareVariable(name); + declareVariable(name); context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0)); TreeExpression initializer = 0; if (hasInitializer) { @@ -759,6 +775,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuild next(); ScopeRef catchScope = pushScope(); catchScope->declareVariable(ident); + catchScope->preventNewDecls(); consumeOrFail(CLOSEPAREN); matchOrFail(OPENBRACE); int initialEvalCount = context.evalCount(); @@ -862,7 +879,7 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame { matchOrFail(IDENT); usesArguments = m_globalData->propertyNames->arguments == *m_token.m_data.ident; - currentScope()->declareVariable(m_token.m_data.ident); + declareVariable(m_token.m_data.ident); TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident); TreeFormalParameterList tail = list; next(); @@ -870,7 +887,7 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame next(); matchOrFail(IDENT); const Identifier* ident = m_token.m_data.ident; - currentScope()->declareVariable(ident); + declareVariable(ident); next(); usesArguments = usesArguments || m_globalData->propertyNames->arguments == *ident; tail = context.createFormalParameterList(tail, *ident); @@ -933,7 +950,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseFunctionDeclaration(Tr int bodyStartLine = 0; failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine))); failIfFalse(name); - currentScope()->declareVariable(name); + declareVariable(name); return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine); } diff --git a/JavaScriptCore/parser/Nodes.h b/JavaScriptCore/parser/Nodes.h index 2d8448c..fa61cdc 100644 --- a/JavaScriptCore/parser/Nodes.h +++ b/JavaScriptCore/parser/Nodes.h @@ -1412,8 +1412,11 @@ namespace JSC { bool usesArguments() const { return m_features & ArgumentsFeature; } void setUsesArguments() { m_features |= ArgumentsFeature; } bool usesThis() const { return m_features & ThisFeature; } + bool needsActivationForMoreThanVariables() const { ASSERT(m_data); return m_features & (EvalFeature | WithFeature | CatchFeature); } bool needsActivation() const { ASSERT(m_data); return (hasCapturedVariables()) || (m_features & (EvalFeature | WithFeature | CatchFeature)); } bool hasCapturedVariables() const { return !!m_data->m_capturedVariables.size(); } + size_t capturedVariableCount() const { return m_data->m_capturedVariables.size(); } + bool captures(const Identifier& ident) { return m_data->m_capturedVariables.contains(ident.impl()); } VarStack& varStack() { ASSERT(m_data); return m_data->m_varStack; } FunctionStack& functionStack() { ASSERT(m_data); return m_data->m_functionStack; } diff --git a/JavaScriptCore/qt/ChangeLog b/JavaScriptCore/qt/ChangeLog index e80493b..11018b4 100644 --- a/JavaScriptCore/qt/ChangeLog +++ b/JavaScriptCore/qt/ChangeLog @@ -1,3 +1,39 @@ +2010-09-29 Caio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org> + + Reviewed by Andreas Kling. + + [Qt] QScriptEngine should have an API for creating Date objects + https://bugs.webkit.org/show_bug.cgi?id=41667 + + Implement newDate(), isDate() and toDateTime() functions. Use the + QDateTime::{to,set}MSecsSinceEpoch() functions to do the + calculations. + + * api/qscriptengine.cpp: + (QScriptEngine::newDate): + * api/qscriptengine.h: + * api/qscriptengine_p.cpp: + (QScriptEnginePrivate::newDate): + * api/qscriptengine_p.h: + (QScriptEnginePrivate::isDate): + + * api/qscriptoriginalglobalobject_p.h: + (QScriptOriginalGlobalObject::QScriptOriginalGlobalObject): need + to keep track of Date Constructor and Prototype. + (QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject): ditto. + (QScriptOriginalGlobalObject::isDate): use the Date Constructor + and Prototype to identify Date values. + + * api/qscriptvalue.cpp: + (QScriptValue::isDate): + (QScriptValue::toDateTime): + * api/qscriptvalue.h: + * api/qscriptvalue_p.h: + (QScriptValuePrivate::isDate): + (QScriptValuePrivate::toDateTime): + * tests/qscriptengine/tst_qscriptengine.cpp: + (tst_QScriptEngine::newDate): + 2010-07-27 Jedrzej Nowacki <jedrzej.nowacki@nokia.com> Reviewed by Kenneth Rohde Christiansen. diff --git a/JavaScriptCore/qt/api/qscriptengine.cpp b/JavaScriptCore/qt/api/qscriptengine.cpp index 7ef7c8e..607b0b9 100644 --- a/JavaScriptCore/qt/api/qscriptengine.cpp +++ b/JavaScriptCore/qt/api/qscriptengine.cpp @@ -25,6 +25,8 @@ #include "qscriptprogram_p.h" #include "qscriptsyntaxcheckresult_p.h" #include "qscriptvalue_p.h" +#include <QtCore/qdatetime.h> +#include <QtCore/qnumeric.h> /*! Constructs a QScriptEngine object. @@ -368,6 +370,27 @@ QScriptValue QScriptEngine::newArray(uint length) } /*! + Creates a QtScript object of class Date with the given \a value + (the number of milliseconds since 01 January 1970, UTC). +*/ +QScriptValue QScriptEngine::newDate(qsreal value) +{ + return QScriptValuePrivate::get(d_ptr->newDate(value)); +} + +/*! + Creates a QtScript object of class Date from the given \a value. + + \sa QScriptValue::toDateTime() +*/ +QScriptValue QScriptEngine::newDate(const QDateTime& value) +{ + if (value.isValid()) + return QScriptValuePrivate::get(d_ptr->newDate(qsreal(value.toMSecsSinceEpoch()))); + return QScriptValuePrivate::get(d_ptr->newDate(qSNaN())); +} + +/*! Returns this engine's Global Object. By default, the Global Object contains the built-in objects that are diff --git a/JavaScriptCore/qt/api/qscriptengine.h b/JavaScriptCore/qt/api/qscriptengine.h index b85dc52..281707f 100644 --- a/JavaScriptCore/qt/api/qscriptengine.h +++ b/JavaScriptCore/qt/api/qscriptengine.h @@ -23,11 +23,12 @@ #include "qscriptprogram.h" #include "qscriptstring.h" #include "qscriptsyntaxcheckresult.h" +#include "qscriptvalue.h" #include <QtCore/qobject.h> #include <QtCore/qshareddata.h> #include <QtCore/qstring.h> -class QScriptValue; +class QDateTime; class QScriptEnginePrivate; // FIXME: Remove this once QScriptContext is properly defined. @@ -69,6 +70,8 @@ public: QScriptValue newObject(); QScriptValue newArray(uint length = 0); + QScriptValue newDate(qsreal value); + QScriptValue newDate(const QDateTime& value); QScriptValue globalObject() const; private: friend class QScriptEnginePrivate; diff --git a/JavaScriptCore/qt/api/qscriptengine_p.cpp b/JavaScriptCore/qt/api/qscriptengine_p.cpp index a708a34..89054c0 100644 --- a/JavaScriptCore/qt/api/qscriptengine_p.cpp +++ b/JavaScriptCore/qt/api/qscriptengine_p.cpp @@ -146,6 +146,20 @@ QScriptValuePrivate* QScriptEnginePrivate::newArray(uint length) return new QScriptValuePrivate(this, array); } +QScriptValuePrivate* QScriptEnginePrivate::newDate(qsreal value) +{ + JSValueRef exception = 0; + JSValueRef argument = JSValueMakeNumber(m_context, value); + JSObjectRef result = JSObjectMakeDate(m_context, /* argumentCount */ 1, &argument, &exception); + + if (exception) { + setException(exception, NotNullException); + return new QScriptValuePrivate(); + } + + return new QScriptValuePrivate(this, result); +} + QScriptValuePrivate* QScriptEnginePrivate::globalObject() const { JSObjectRef globalObject = JSContextGetGlobalObject(m_context); diff --git a/JavaScriptCore/qt/api/qscriptengine_p.h b/JavaScriptCore/qt/api/qscriptengine_p.h index eec1929..4603b91 100644 --- a/JavaScriptCore/qt/api/qscriptengine_p.h +++ b/JavaScriptCore/qt/api/qscriptengine_p.h @@ -77,16 +77,19 @@ public: QScriptValuePrivate* newObject() const; QScriptValuePrivate* newArray(uint length); + QScriptValuePrivate* newDate(qsreal value); QScriptValuePrivate* globalObject() const; inline QScriptStringPrivate* toStringHandle(const QString& str) const; inline operator JSGlobalContextRef() const; + inline bool isDate(JSValueRef value) const; inline bool isArray(JSValueRef value) const; inline bool isError(JSValueRef value) const; inline bool objectHasOwnProperty(JSObjectRef object, JSStringRef property) const; inline QVector<JSStringRef> objectGetOwnPropertyNames(JSObjectRef object) const; + private: QScriptEngine* q_ptr; JSGlobalContextRef m_context; @@ -226,6 +229,11 @@ QScriptEnginePrivate::operator JSGlobalContextRef() const return m_context; } +bool QScriptEnginePrivate::isDate(JSValueRef value) const +{ + return m_originalGlobalObject.isDate(value); +} + bool QScriptEnginePrivate::isArray(JSValueRef value) const { return m_originalGlobalObject.isArray(value); diff --git a/JavaScriptCore/qt/api/qscriptoriginalglobalobject_p.h b/JavaScriptCore/qt/api/qscriptoriginalglobalobject_p.h index 31e94f7..2bd945f 100644 --- a/JavaScriptCore/qt/api/qscriptoriginalglobalobject_p.h +++ b/JavaScriptCore/qt/api/qscriptoriginalglobalobject_p.h @@ -43,6 +43,7 @@ public: inline bool objectHasOwnProperty(JSObjectRef object, JSStringRef property) const; inline QVector<JSStringRef> objectGetOwnPropertyNames(JSObjectRef object) const; + inline bool isDate(JSValueRef value) const; inline bool isArray(JSValueRef value) const; inline bool isError(JSValueRef value) const; @@ -61,6 +62,8 @@ private: JSValueRef m_errorPrototype; JSObjectRef m_functionConstructor; JSValueRef m_functionPrototype; + JSObjectRef m_dateConstructor; + JSValueRef m_datePrototype; // Reference to standard JS functions that are not exposed by JSC C API. JSObjectRef m_hasOwnPropertyFunction; @@ -78,6 +81,7 @@ QScriptOriginalGlobalObject::QScriptOriginalGlobalObject(JSGlobalContextRef cont initializeMember(globalObject, propertyName.get(), "Array", m_arrayConstructor, m_arrayPrototype); initializeMember(globalObject, propertyName.get(), "Error", m_errorConstructor, m_errorPrototype); initializeMember(globalObject, propertyName.get(), "Function", m_functionConstructor, m_functionPrototype); + initializeMember(globalObject, propertyName.get(), "Date", m_dateConstructor, m_datePrototype); propertyName.adopt(JSStringCreateWithUTF8CString("hasOwnProperty")); m_hasOwnPropertyFunction = const_cast<JSObjectRef>(JSObjectGetProperty(m_context, globalObject, propertyName.get(), &exception)); @@ -126,6 +130,8 @@ QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject() JSValueUnprotect(m_context, m_errorPrototype); JSValueUnprotect(m_context, m_functionConstructor); JSValueUnprotect(m_context, m_functionPrototype); + JSValueUnprotect(m_context, m_dateConstructor); + JSValueUnprotect(m_context, m_datePrototype); JSValueUnprotect(m_context, m_hasOwnPropertyFunction); JSValueUnprotect(m_context, m_getOwnPropertyNamesFunction); JSGlobalContextRelease(m_context); @@ -170,6 +176,11 @@ inline QVector<JSStringRef> QScriptOriginalGlobalObject::objectGetOwnPropertyNam return names; } +inline bool QScriptOriginalGlobalObject::isDate(JSValueRef value) const +{ + return isType(value, m_dateConstructor, m_datePrototype); +} + inline bool QScriptOriginalGlobalObject::isArray(JSValueRef value) const { return isType(value, m_arrayConstructor, m_arrayPrototype); diff --git a/JavaScriptCore/qt/api/qscriptvalue.cpp b/JavaScriptCore/qt/api/qscriptvalue.cpp index a7d0b7b..8a7a6c4 100644 --- a/JavaScriptCore/qt/api/qscriptvalue.cpp +++ b/JavaScriptCore/qt/api/qscriptvalue.cpp @@ -324,6 +324,17 @@ bool QScriptValue::isArray() const } /*! + Returns true if this QScriptValue is an object of the Date class; + otherwise returns false. + + \sa QScriptEngine::newDate() +*/ +bool QScriptValue::isDate() const +{ + return d_ptr->isDate(); +} + +/*! Returns true if this QScriptValue is of the Object type; otherwise returns false. @@ -488,6 +499,18 @@ QScriptValue QScriptValue::toObject() const } /*! + Returns a QDateTime representation of this value, in local time. + If this QScriptValue is not a date, or the value of the date is + NaN (Not-a-Number), an invalid QDateTime is returned. + + \sa isDate() +*/ +QDateTime QScriptValue::toDateTime() const +{ + return d_ptr->toDateTime(); +} + +/*! Calls this QScriptValue as a function, using \a thisObject as the `this' object in the function call, and passing \a args as arguments to the function. Returns the value returned from diff --git a/JavaScriptCore/qt/api/qscriptvalue.h b/JavaScriptCore/qt/api/qscriptvalue.h index 991a6a0..bd33849 100644 --- a/JavaScriptCore/qt/api/qscriptvalue.h +++ b/JavaScriptCore/qt/api/qscriptvalue.h @@ -26,6 +26,7 @@ class QScriptEngine; class QScriptValuePrivate; +class QDateTime; class QScriptValue; typedef QList<QScriptValue> QScriptValueList; @@ -112,6 +113,7 @@ public: bool isObject() const; bool isError() const; bool isArray() const; + bool isDate() const; QString toString() const; qsreal toNumber() const; @@ -122,6 +124,7 @@ public: quint32 toUInt32() const; quint16 toUInt16() const; QScriptValue toObject() const; + QDateTime toDateTime() const; QScriptValue call(const QScriptValue& thisObject = QScriptValue(), const QScriptValueList& args = QScriptValueList()); diff --git a/JavaScriptCore/qt/api/qscriptvalue_p.h b/JavaScriptCore/qt/api/qscriptvalue_p.h index 6fbf98b..f98a06a 100644 --- a/JavaScriptCore/qt/api/qscriptvalue_p.h +++ b/JavaScriptCore/qt/api/qscriptvalue_p.h @@ -26,6 +26,7 @@ #include <JavaScriptCore/JavaScript.h> #include <JavaScriptCore/JSRetainPtr.h> #include <JSObjectRefPrivate.h> +#include <QtCore/qdatetime.h> #include <QtCore/qmath.h> #include <QtCore/qnumeric.h> #include <QtCore/qshareddata.h> @@ -102,6 +103,7 @@ public: inline bool isObject(); inline bool isFunction(); inline bool isArray(); + inline bool isDate(); inline QString toString() const; inline qsreal toNumber() const; @@ -113,6 +115,7 @@ public: inline QScriptValuePrivate* toObject(QScriptEnginePrivate* engine); inline QScriptValuePrivate* toObject(); + inline QDateTime toDateTime(); inline QScriptValuePrivate* prototype(); inline void setPrototype(QScriptValuePrivate* prototype); @@ -462,6 +465,20 @@ bool QScriptValuePrivate::isArray() } } +bool QScriptValuePrivate::isDate() +{ + switch (m_state) { + case JSValue: + if (refinedJSValue() != JSObject) + return false; + // Fall-through. + case JSObject: + return m_engine->isDate(*this); + default: + return false; + } +} + QString QScriptValuePrivate::toString() const { switch (m_state) { @@ -662,6 +679,24 @@ QScriptValuePrivate* QScriptValuePrivate::toObject() return new QScriptValuePrivate; } +QDateTime QScriptValuePrivate::toDateTime() +{ + if (!isDate()) + return QDateTime(); + + JSValueRef exception = 0; + qsreal t = JSValueToNumber(*m_engine, *this, &exception); + + if (exception) { + m_engine->setException(exception, QScriptEnginePrivate::NotNullException); + return QDateTime(); + } + + QDateTime result; + result.setMSecsSinceEpoch(qint64(t)); + return result; +} + inline QScriptValuePrivate* QScriptValuePrivate::prototype() { if (isObject()) { diff --git a/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp b/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp index 58a1587..dabcfb2 100644 --- a/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp +++ b/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp @@ -21,6 +21,7 @@ #include "qscriptprogram.h" #include "qscriptsyntaxcheckresult.h" #include "qscriptvalue.h" +#include <QtCore/qnumeric.h> #include <QtTest/qtest.h> class tst_QScriptEngine : public QObject { @@ -50,6 +51,7 @@ private slots: void toObjectTwoEngines(); void newArray(); void uncaughtException(); + void newDate(); }; /* Evaluating a script that throw an unhandled exception should return an invalid value. */ @@ -681,5 +683,52 @@ void tst_QScriptEngine::uncaughtException() } } +void tst_QScriptEngine::newDate() +{ + QScriptEngine eng; + { + QScriptValue date = eng.newDate(0); + QCOMPARE(date.isValid(), true); + QCOMPARE(date.isDate(), true); + QCOMPARE(date.isObject(), true); + QVERIFY(!date.isFunction()); + // prototype should be Date.prototype + QCOMPARE(date.prototype().isValid(), true); + QCOMPARE(date.prototype().isDate(), true); + QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true); + } + { + QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::LocalTime); + QScriptValue date = eng.newDate(dt); + QCOMPARE(date.isValid(), true); + QCOMPARE(date.isDate(), true); + QCOMPARE(date.isObject(), true); + // prototype should be Date.prototype + QCOMPARE(date.prototype().isValid(), true); + QCOMPARE(date.prototype().isDate(), true); + QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true); + + QCOMPARE(date.toDateTime(), dt); + } + { + QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::UTC); + QScriptValue date = eng.newDate(dt); + // toDateTime() result should be in local time + QCOMPARE(date.toDateTime(), dt.toLocalTime()); + } + // Date.parse() should return NaN when it fails + { + QScriptValue ret = eng.evaluate("Date.parse()"); + QVERIFY(ret.isNumber()); + QVERIFY(qIsNaN(ret.toNumber())); + } + // Date.parse() should be able to parse the output of Date().toString() + { + QScriptValue ret = eng.evaluate("var x = new Date(); var s = x.toString(); s == new Date(Date.parse(s)).toString()"); + QVERIFY(ret.isBoolean()); + QCOMPARE(ret.toBoolean(), true); + } +} + QTEST_MAIN(tst_QScriptEngine) #include "tst_qscriptengine.moc" diff --git a/JavaScriptCore/runtime/Arguments.h b/JavaScriptCore/runtime/Arguments.h index d892de0..49c8b3b 100644 --- a/JavaScriptCore/runtime/Arguments.h +++ b/JavaScriptCore/runtime/Arguments.h @@ -225,7 +225,7 @@ namespace JSC { ASSERT(!d()->registerArray); size_t numParametersMinusThis = d()->functionExecutable->parameterCount(); - size_t numVars = d()->functionExecutable->variableCount(); + size_t numVars = d()->functionExecutable->capturedVariableCount(); size_t numLocals = numVars + numParametersMinusThis; if (!numLocals) diff --git a/JavaScriptCore/runtime/DateConstructor.cpp b/JavaScriptCore/runtime/DateConstructor.cpp index 5b2f916..49e0405 100644 --- a/JavaScriptCore/runtime/DateConstructor.cpp +++ b/JavaScriptCore/runtime/DateConstructor.cpp @@ -90,25 +90,34 @@ JSObject* constructDate(ExecState* exec, const ArgList& args) value = primitive.toNumber(exec); } } else { - if (isnan(args.at(0).toNumber(exec)) - || isnan(args.at(1).toNumber(exec)) - || (numArgs >= 3 && isnan(args.at(2).toNumber(exec))) - || (numArgs >= 4 && isnan(args.at(3).toNumber(exec))) - || (numArgs >= 5 && isnan(args.at(4).toNumber(exec))) - || (numArgs >= 6 && isnan(args.at(5).toNumber(exec))) - || (numArgs >= 7 && isnan(args.at(6).toNumber(exec)))) + double doubleArguments[7] = { + args.at(0).toNumber(exec), + args.at(1).toNumber(exec), + args.at(2).toNumber(exec), + args.at(3).toNumber(exec), + args.at(4).toNumber(exec), + args.at(5).toNumber(exec), + args.at(6).toNumber(exec) + }; + if (isnan(doubleArguments[0]) + || isnan(doubleArguments[1]) + || (numArgs >= 3 && isnan(doubleArguments[2])) + || (numArgs >= 4 && isnan(doubleArguments[3])) + || (numArgs >= 5 && isnan(doubleArguments[4])) + || (numArgs >= 6 && isnan(doubleArguments[5])) + || (numArgs >= 7 && isnan(doubleArguments[6]))) value = NaN; else { GregorianDateTime t; - int year = args.at(0).toInt32(exec); + int year = JSC::toInt32(doubleArguments[0]); t.year = (year >= 0 && year <= 99) ? year : year - 1900; - t.month = args.at(1).toInt32(exec); - t.monthDay = (numArgs >= 3) ? args.at(2).toInt32(exec) : 1; - t.hour = args.at(3).toInt32(exec); - t.minute = args.at(4).toInt32(exec); - t.second = args.at(5).toInt32(exec); + t.month = JSC::toInt32(doubleArguments[1]); + t.monthDay = (numArgs >= 3) ? JSC::toInt32(doubleArguments[2]) : 1; + t.hour = JSC::toInt32(doubleArguments[3]); + t.minute = JSC::toInt32(doubleArguments[4]); + t.second = JSC::toInt32(doubleArguments[5]); t.isDST = -1; - double ms = (numArgs >= 7) ? args.at(6).toNumber(exec) : 0; + double ms = (numArgs >= 7) ? doubleArguments[6] : 0; value = gregorianDateTimeToMS(exec, t, ms, false); } } @@ -160,25 +169,34 @@ static EncodedJSValue JSC_HOST_CALL dateNow(ExecState* exec) static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState* exec) { + double doubleArguments[7] = { + exec->argument(0).toNumber(exec), + exec->argument(1).toNumber(exec), + exec->argument(2).toNumber(exec), + exec->argument(3).toNumber(exec), + exec->argument(4).toNumber(exec), + exec->argument(5).toNumber(exec), + exec->argument(6).toNumber(exec) + }; int n = exec->argumentCount(); - if (isnan(exec->argument(0).toNumber(exec)) - || isnan(exec->argument(1).toNumber(exec)) - || (n >= 3 && isnan(exec->argument(2).toNumber(exec))) - || (n >= 4 && isnan(exec->argument(3).toNumber(exec))) - || (n >= 5 && isnan(exec->argument(4).toNumber(exec))) - || (n >= 6 && isnan(exec->argument(5).toNumber(exec))) - || (n >= 7 && isnan(exec->argument(6).toNumber(exec)))) + if (isnan(doubleArguments[0]) + || isnan(doubleArguments[1]) + || (n >= 3 && isnan(doubleArguments[2])) + || (n >= 4 && isnan(doubleArguments[3])) + || (n >= 5 && isnan(doubleArguments[4])) + || (n >= 6 && isnan(doubleArguments[5])) + || (n >= 7 && isnan(doubleArguments[6]))) return JSValue::encode(jsNaN(exec)); GregorianDateTime t; - int year = exec->argument(0).toInt32(exec); + int year = JSC::toInt32(doubleArguments[0]); t.year = (year >= 0 && year <= 99) ? year : year - 1900; - t.month = exec->argument(1).toInt32(exec); - t.monthDay = (n >= 3) ? exec->argument(2).toInt32(exec) : 1; - t.hour = exec->argument(3).toInt32(exec); - t.minute = exec->argument(4).toInt32(exec); - t.second = exec->argument(5).toInt32(exec); - double ms = (n >= 7) ? exec->argument(6).toNumber(exec) : 0; + t.month = JSC::toInt32(doubleArguments[1]); + t.monthDay = (n >= 3) ? JSC::toInt32(doubleArguments[2]) : 1; + t.hour = JSC::toInt32(doubleArguments[3]); + t.minute = JSC::toInt32(doubleArguments[4]); + t.second = JSC::toInt32(doubleArguments[5]); + double ms = (n >= 7) ? doubleArguments[6] : 0; return JSValue::encode(jsNumber(exec, timeClip(gregorianDateTimeToMS(exec, t, ms, true)))); } diff --git a/JavaScriptCore/runtime/Executable.cpp b/JavaScriptCore/runtime/Executable.cpp index e14955c..871f3e2 100644 --- a/JavaScriptCore/runtime/Executable.cpp +++ b/JavaScriptCore/runtime/Executable.cpp @@ -65,7 +65,7 @@ ProgramExecutable::~ProgramExecutable() FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) : ScriptExecutable(globalData, source) - , m_numVariables(0) + , m_numCapturedVariables(0) , m_forceUsesArguments(forceUsesArguments) , m_parameters(parameters) , m_name(name) @@ -77,7 +77,7 @@ FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifie FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) : ScriptExecutable(exec, source) - , m_numVariables(0) + , m_numCapturedVariables(0) , m_forceUsesArguments(forceUsesArguments) , m_parameters(parameters) , m_name(name) @@ -197,7 +197,7 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain generator->generate(); m_numParametersForCall = m_codeBlockForCall->m_numParameters; ASSERT(m_numParametersForCall); - m_numVariables = m_codeBlockForCall->m_numVars; + m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars; m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); body->destroyData(); @@ -238,7 +238,7 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope generator->generate(); m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters; ASSERT(m_numParametersForConstruct); - m_numVariables = m_codeBlockForConstruct->m_numVars; + m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars; m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); body->destroyData(); diff --git a/JavaScriptCore/runtime/Executable.h b/JavaScriptCore/runtime/Executable.h index c168ac8..feab7ef 100644 --- a/JavaScriptCore/runtime/Executable.h +++ b/JavaScriptCore/runtime/Executable.h @@ -144,6 +144,7 @@ namespace JSC { , m_features(0) { #if ENABLE(CODEBLOCK_SAMPLING) + relaxAdoptionRequirement(); if (SamplingTool* sampler = globalData->interpreter->sampler()) sampler->notifyOfScope(this); #else @@ -157,6 +158,7 @@ namespace JSC { , m_features(0) { #if ENABLE(CODEBLOCK_SAMPLING) + relaxAdoptionRequirement(); if (SamplingTool* sampler = exec->globalData().interpreter->sampler()) sampler->notifyOfScope(this); #else @@ -347,7 +349,7 @@ namespace JSC { const Identifier& name() { return m_name; } size_t parameterCount() const { return m_parameters->size(); } - unsigned variableCount() const { return m_numVariables; } + unsigned capturedVariableCount() const { return m_numCapturedVariables; } UString paramString() const; SharedSymbolTable* symbolTable() const { return m_symbolTable; } @@ -364,7 +366,7 @@ namespace JSC { virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); - unsigned m_numVariables : 31; + unsigned m_numCapturedVariables : 31; bool m_forceUsesArguments : 1; RefPtr<FunctionParameters> m_parameters; diff --git a/JavaScriptCore/runtime/JSActivation.cpp b/JavaScriptCore/runtime/JSActivation.cpp index 8cf71d0..d121518 100644 --- a/JavaScriptCore/runtime/JSActivation.cpp +++ b/JavaScriptCore/runtime/JSActivation.cpp @@ -62,12 +62,65 @@ void JSActivation::markChildren(MarkStack& markStack) size_t count = numParametersMinusThis; markStack.appendValues(registerArray, count); - size_t numVars = d()->functionExecutable->variableCount(); + size_t numVars = d()->functionExecutable->capturedVariableCount(); // Skip the call frame, which sits between the parameters and vars. markStack.appendValues(registerArray + count + RegisterFile::CallFrameHeaderSize, numVars, MayContainNullValues); } +inline bool JSActivation::symbolTableGet(const Identifier& propertyName, PropertySlot& slot) +{ + SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl()); + if (!entry.isNull()) { + ASSERT(entry.getIndex() < static_cast<int>(d()->functionExecutable->capturedVariableCount())); + slot.setRegisterSlot(®isterAt(entry.getIndex())); + return true; + } + return false; +} + +inline bool JSActivation::symbolTablePut(const Identifier& propertyName, JSValue value) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl()); + if (entry.isNull()) + return false; + if (entry.isReadOnly()) + return true; + ASSERT(entry.getIndex() < static_cast<int>(d()->functionExecutable->capturedVariableCount())); + registerAt(entry.getIndex()) = value; + return true; +} + +void JSActivation::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + SymbolTable::const_iterator end = symbolTable().end(); + for (SymbolTable::const_iterator it = symbolTable().begin(); it != end; ++it) { + ASSERT(it->second.getIndex() < static_cast<int>(d()->functionExecutable->capturedVariableCount())); + if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) + propertyNames.add(Identifier(exec, it->first.get())); + } + // Skip the JSVariableObject implementation of getOwnPropertyNames + JSObject::getOwnPropertyNames(exec, propertyNames, mode); +} + +inline bool JSActivation::symbolTablePutWithAttributes(const Identifier& propertyName, JSValue value, unsigned attributes) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + SymbolTable::iterator iter = symbolTable().find(propertyName.impl()); + if (iter == symbolTable().end()) + return false; + SymbolTableEntry& entry = iter->second; + ASSERT(!entry.isNull()); + if (entry.getIndex() >= static_cast<int>(d()->functionExecutable->capturedVariableCount())) + return false; + entry.setAttributes(attributes); + registerAt(entry.getIndex()) = value; + return true; +} + bool JSActivation::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { if (propertyName == exec->propertyNames().arguments) { diff --git a/JavaScriptCore/runtime/JSActivation.h b/JavaScriptCore/runtime/JSActivation.h index d5e7991..9ff9168 100644 --- a/JavaScriptCore/runtime/JSActivation.h +++ b/JavaScriptCore/runtime/JSActivation.h @@ -52,6 +52,7 @@ namespace JSC { virtual bool isActivationObject() const { return true; } virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode); virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); @@ -87,7 +88,13 @@ namespace JSC { RefPtr<FunctionExecutable> functionExecutable; }; - + + bool symbolTableGet(const Identifier&, PropertySlot&); + bool symbolTableGet(const Identifier&, PropertyDescriptor&); + bool symbolTableGet(const Identifier&, PropertySlot&, bool& slotIsWriteable); + bool symbolTablePut(const Identifier&, JSValue); + bool symbolTablePutWithAttributes(const Identifier&, JSValue, unsigned attributes); + static JSValue argumentsGetter(ExecState*, JSValue, const Identifier&); NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter(); diff --git a/JavaScriptCore/runtime/JSArray.cpp b/JavaScriptCore/runtime/JSArray.cpp index 340cb75..dae807f 100644 --- a/JavaScriptCore/runtime/JSArray.cpp +++ b/JavaScriptCore/runtime/JSArray.cpp @@ -202,12 +202,20 @@ JSArray::JSArray(NonNullPassRefPtr<Structure> structure, const ArgList& list) : JSObject(structure) { unsigned initialCapacity = list.size(); - - m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity))); + unsigned initialStorage; + + // If the ArgList is empty, allocate space for 3 entries. This value empirically + // works well for benchmarks. + if (!initialCapacity) + initialStorage = 3; + else + initialStorage = initialCapacity; + + m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialStorage))); m_storage->m_allocBase = m_storage; m_indexBias = 0; m_storage->m_length = initialCapacity; - m_vectorLength = initialCapacity; + m_vectorLength = initialStorage; m_storage->m_numValuesInVector = initialCapacity; m_storage->m_sparseValueMap = 0; m_storage->subclassData = 0; @@ -221,10 +229,12 @@ JSArray::JSArray(NonNullPassRefPtr<Structure> structure, const ArgList& list) ArgList::const_iterator end = list.end(); for (ArgList::const_iterator it = list.begin(); it != end; ++it, ++i) vector[i] = *it; + for (; i < initialStorage; i++) + vector[i] = JSValue(); checkConsistency(); - Heap::heap(this)->reportExtraMemoryCost(storageSize(initialCapacity)); + Heap::heap(this)->reportExtraMemoryCost(storageSize(initialStorage)); } JSArray::~JSArray() diff --git a/JavaScriptCore/runtime/JSCell.h b/JavaScriptCore/runtime/JSCell.h index 2ffce8d..cfa1454 100644 --- a/JavaScriptCore/runtime/JSCell.h +++ b/JavaScriptCore/runtime/JSCell.h @@ -34,7 +34,24 @@ namespace JSC { - class JSCell : public NoncopyableCustomAllocated { +#if COMPILER(MSVC) + // If WTF_MAKE_NONCOPYABLE is applied to JSCell we end up with a bunch of + // undefined references to the JSCell copy constructor and assignment operator + // when linking JavaScriptCore. + class MSVCBugWorkaround { + WTF_MAKE_NONCOPYABLE(MSVCBugWorkaround); + + protected: + MSVCBugWorkaround() { } + ~MSVCBugWorkaround() { } + }; + + class JSCell : MSVCBugWorkaround { +#else + class JSCell { + WTF_MAKE_NONCOPYABLE(JSCell); +#endif + friend class GetterSetter; friend class Heap; friend class JIT; diff --git a/JavaScriptCore/runtime/MathObject.cpp b/JavaScriptCore/runtime/MathObject.cpp index 5648264..8d2ae2d 100644 --- a/JavaScriptCore/runtime/MathObject.cpp +++ b/JavaScriptCore/runtime/MathObject.cpp @@ -135,7 +135,9 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState* exec) EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState* exec) { - return JSValue::encode(jsDoubleNumber(exec, atan2(exec->argument(0).toNumber(exec), exec->argument(1).toNumber(exec)))); + double arg0 = exec->argument(0).toNumber(exec); + double arg1 = exec->argument(1).toNumber(exec); + return JSValue::encode(jsDoubleNumber(exec, atan2(arg0, arg1))); } EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec) diff --git a/JavaScriptCore/runtime/RegExp.cpp b/JavaScriptCore/runtime/RegExp.cpp index d4545cb..3ebfe0f 100644 --- a/JavaScriptCore/runtime/RegExp.cpp +++ b/JavaScriptCore/runtime/RegExp.cpp @@ -115,8 +115,6 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector) { if (startOffset < 0) startOffset = 0; - if (ovector) - ovector->resize(0); #if ENABLE(REGEXP_TRACING) m_rtMatchCallCount++; @@ -142,7 +140,10 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector) } ASSERT(offsetVector); - for (int j = 0; j < offsetVectorSize; ++j) + // Initialize offsetVector with the return value (index 0) and the + // first subpattern start indicies (even index values) set to -1. + // No need to init the subpattern end indicies. + for (unsigned j = 0, i = 0; i < m_numSubpatterns + 1; j += 2, i++) offsetVector[j] = -1; #if ENABLE(YARR_JIT) @@ -157,8 +158,6 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector) if (result != -1) fprintf(stderr, "jsRegExpExecute failed with result %d\n", result); #endif - if (ovector) - ovector->clear(); } #if ENABLE(REGEXP_TRACING) @@ -255,7 +254,7 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector) if (codeBlock.getFallback()) sprintf(jitAddr, "fallback"); else - sprintf(jitAddr, "0x%014lx", (uintptr_t)codeBlock.getAddr()); + sprintf(jitAddr, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.getAddr())); #else const char* jitAddr = "JIT Off"; #endif diff --git a/JavaScriptCore/wtf/Assertions.cpp b/JavaScriptCore/wtf/Assertions.cpp index 273e0e0..9222c1d 100644 --- a/JavaScriptCore/wtf/Assertions.cpp +++ b/JavaScriptCore/wtf/Assertions.cpp @@ -42,12 +42,11 @@ #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0500 #endif -#include <windows.h> #include <crtdbg.h> #endif -#if OS(WINCE) -#include <winbase.h> +#if OS(WINDOWS) +#include <windows.h> #endif #if PLATFORM(BREWMP) @@ -113,7 +112,7 @@ static void vprintf_stderr_common(const char* format, va_list args) printLog(buffer); } -#elif COMPILER(MSVC) && !defined(WINCEBASIC) +#elif HAVE(ISDEBUGGERPRESENT) if (IsDebuggerPresent()) { size_t size = 1024; diff --git a/JavaScriptCore/wtf/Noncopyable.h b/JavaScriptCore/wtf/Noncopyable.h index 60a46e2..898c1ba 100644 --- a/JavaScriptCore/wtf/Noncopyable.h +++ b/JavaScriptCore/wtf/Noncopyable.h @@ -21,6 +21,26 @@ #ifndef WTF_Noncopyable_h #define WTF_Noncopyable_h +#ifndef __has_feature + #define __has_feature(x) 0 +#endif + +#if __has_feature(cxx_deleted_functions) + #define WTF_MAKE_NONCOPYABLE(ClassName) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") \ + _Pragma("clang diagnostic ignored \"-Wc++0x-extensions\"") \ + private: \ + ClassName(const ClassName&) = delete; \ + ClassName& operator=(const ClassName&) = delete; \ + _Pragma("clang diagnostic pop") +#else + #define WTF_MAKE_NONCOPYABLE(ClassName) \ + private: \ + ClassName(const ClassName&); \ + ClassName& operator=(const ClassName&) +#endif + // We don't want argument-dependent lookup to pull in everything from the WTF // namespace when you use Noncopyable, so put it in its own namespace. @@ -36,17 +56,8 @@ namespace WTFNoncopyable { ~Noncopyable() { } }; - class NoncopyableCustomAllocated { - NoncopyableCustomAllocated(const NoncopyableCustomAllocated&); - NoncopyableCustomAllocated& operator=(const NoncopyableCustomAllocated&); - protected: - NoncopyableCustomAllocated() { } - ~NoncopyableCustomAllocated() { } - }; - } // namespace WTFNoncopyable using WTFNoncopyable::Noncopyable; -using WTFNoncopyable::NoncopyableCustomAllocated; #endif // WTF_Noncopyable_h diff --git a/JavaScriptCore/wtf/PassRefPtr.h b/JavaScriptCore/wtf/PassRefPtr.h index b43c5ba..052d6e2 100644 --- a/JavaScriptCore/wtf/PassRefPtr.h +++ b/JavaScriptCore/wtf/PassRefPtr.h @@ -48,13 +48,13 @@ namespace WTF { template<typename T> REF_DEREF_INLINE void refIfNotNull(T* ptr) { - if (UNLIKELY(ptr != 0)) + if (LIKELY(ptr != 0)) ptr->ref(); } template<typename T> REF_DEREF_INLINE void derefIfNotNull(T* ptr) { - if (UNLIKELY(ptr != 0)) + if (LIKELY(ptr != 0)) ptr->deref(); } diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h index 30bc795..1843bea 100644 --- a/JavaScriptCore/wtf/Platform.h +++ b/JavaScriptCore/wtf/Platform.h @@ -746,6 +746,7 @@ #else #define HAVE_SYS_TIMEB_H 1 #define HAVE_ALIGNED_MALLOC 1 +#define HAVE_ISDEBUGGERPRESENT 1 #endif #define HAVE_VIRTUALALLOC 1 @@ -964,7 +965,8 @@ /* The JIT is enabled by default on all x86, x64-64, ARM & MIPS platforms. */ #if !defined(ENABLE_JIT) \ && (CPU(X86) || CPU(X86_64) || CPU(ARM) || CPU(MIPS)) \ - && (OS(DARWIN) || !COMPILER(GCC) || GCC_VERSION_AT_LEAST(4,1,0)) + && (OS(DARWIN) || !COMPILER(GCC) || GCC_VERSION_AT_LEAST(4,1,0)) \ + && !OS(WINCE) #define ENABLE_JIT 1 #endif @@ -1142,7 +1144,7 @@ #define ENABLE_BRANCH_COMPACTION 1 #endif -#if PLATFORM(GTK) || (PLATFORM(EFL) && ENABLE(GLIB_SUPPORT)) +#if ENABLE(GLIB_SUPPORT) #include "GTypedefs.h" #endif diff --git a/JavaScriptCore/wtf/RefCounted.h b/JavaScriptCore/wtf/RefCounted.h index d85c47e..8d8b302 100644 --- a/JavaScriptCore/wtf/RefCounted.h +++ b/JavaScriptCore/wtf/RefCounted.h @@ -145,7 +145,9 @@ protected: } }; -template<typename T> class RefCountedCustomAllocated : public RefCountedBase, public NoncopyableCustomAllocated { +template<typename T> class RefCountedCustomAllocated : public RefCountedBase { + WTF_MAKE_NONCOPYABLE(RefCountedCustomAllocated); + public: void deref() { diff --git a/JavaScriptCore/wtf/StringHashFunctions.h b/JavaScriptCore/wtf/StringHashFunctions.h index 07f117f..3ad7701 100644 --- a/JavaScriptCore/wtf/StringHashFunctions.h +++ b/JavaScriptCore/wtf/StringHashFunctions.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2005, 2006, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,130 +28,142 @@ namespace WTF { // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's static const unsigned stringHashingStartValue = 0x9e3779b9U; -// stringHash methods based on Paul Hsieh's SuperFastHash. +// Paul Hsieh's SuperFastHash // http://www.azillionmonkeys.com/qed/hash.html // char* data is interpreted as latin-encoded (zero extended to 16 bits). +class StringHasher { +public: + inline StringHasher() + : m_hash(stringHashingStartValue) + , m_hasPendingCharacter(false) + , m_pendingCharacter(0) + { + } -inline unsigned stringHash(const UChar* data, unsigned length) -{ - unsigned hash = WTF::stringHashingStartValue; - unsigned rem = length & 1; - length >>= 1; - - // Main loop - for (; length > 0; length--) { - hash += data[0]; - unsigned tmp = (data[1] << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2; - hash += hash >> 11; + inline void addCharacters(UChar a, UChar b) + { + ASSERT(!m_hasPendingCharacter); + addCharactersToHash(a, b); } - // Handle end case - if (rem) { - hash += data[0]; - hash ^= hash << 11; - hash += hash >> 17; + inline void addCharacter(UChar ch) + { + if (m_hasPendingCharacter) { + addCharactersToHash(m_pendingCharacter, ch); + m_hasPendingCharacter = false; + return; + } + + m_pendingCharacter = ch; + m_hasPendingCharacter = true; } - // Force "avalanching" of final 127 bits - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 2; - hash += hash >> 15; - hash ^= hash << 10; - - hash &= 0x7fffffff; - - // this avoids ever returning a hash code of 0, since that is used to - // signal "hash not computed yet", using a value that is likely to be - // effectively the same as 0 when the low bits are masked - if (hash == 0) - hash = 0x40000000; - - return hash; -} - -inline unsigned stringHash(const char* data, unsigned length) -{ - unsigned hash = WTF::stringHashingStartValue; - unsigned rem = length & 1; - length >>= 1; - - // Main loop - for (; length > 0; length--) { - hash += static_cast<unsigned char>(data[0]); - unsigned tmp = (static_cast<unsigned char>(data[1]) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2; - hash += hash >> 11; + inline unsigned hash() const + { + unsigned result = m_hash; + + // Handle end case. + if (m_hasPendingCharacter) { + result += m_pendingCharacter; + result ^= result << 11; + result += result >> 17; + } + + // Force "avalanching" of final 31 bits. + result ^= result << 3; + result += result >> 5; + result ^= result << 2; + result += result >> 15; + result ^= result << 10; + + // First bit is used in UStringImpl for m_isIdentifier. + result &= 0x7fffffff; + + // This avoids ever returning a hash code of 0, since that is used to + // signal "hash not computed yet", using a value that is likely to be + // effectively the same as 0 when the low bits are masked. + if (!result) + return 0x40000000; + + return result; } - // Handle end case - if (rem) { - hash += static_cast<unsigned char>(data[0]); - hash ^= hash << 11; - hash += hash >> 17; + template<typename T, UChar Converter(T)> static inline unsigned createHash(const T* data, unsigned length) + { + StringHasher hasher; + bool rem = length & 1; + length >>= 1; + + while (length--) { + hasher.addCharacters(Converter(data[0]), Converter(data[1])); + data += 2; + } + + if (rem) + hasher.addCharacter(Converter(*data)); + + return hasher.hash(); } - // Force "avalanching" of final 127 bits - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 2; - hash += hash >> 15; - hash ^= hash << 10; - - hash &= 0x7fffffff; - - // this avoids ever returning a hash code of 0, since that is used to - // signal "hash not computed yet", using a value that is likely to be - // effectively the same as 0 when the low bits are masked - if (hash == 0) - hash = 0x40000000; - - return hash; -} - -inline unsigned stringHash(const char* data) -{ - unsigned hash = WTF::stringHashingStartValue; - - // Main loop - for (;;) { - unsigned char b0 = data[0]; - if (!b0) - break; - unsigned char b1 = data[1]; - if (!b1) { - hash += b0; - hash ^= hash << 11; - hash += hash >> 17; - break; + template<typename T, UChar Converter(T)> static inline unsigned createHash(const T* data) + { + StringHasher hasher; + + while (true) { + UChar b0 = Converter(*data++); + if (!b0) + break; + UChar b1 = Converter(*data++); + if (!b1) { + hasher.addCharacter(b0); + break; + } + + hasher.addCharacters(b0, b1); } - hash += b0; - unsigned tmp = (b1 << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2; - hash += hash >> 11; + + return hasher.hash(); + } + + template<typename T> static inline unsigned createHash(const T* data, unsigned length) + { + return createHash<T, defaultCoverter>(data, length); } - // Force "avalanching" of final 127 bits. - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 2; - hash += hash >> 15; - hash ^= hash << 10; + template<typename T> static inline unsigned createHash(const T* data) + { + return createHash<T, defaultCoverter>(data); + } - hash &= 0x7fffffff; + template<size_t length> static inline unsigned createBlobHash(const void* data) + { + COMPILE_ASSERT(!(length % 4), length_must_be_a_multible_of_four); + return createHash<UChar>(static_cast<const UChar*>(data), length / sizeof(UChar)); + } - // This avoids ever returning a hash code of 0, since that is used to - // signal "hash not computed yet", using a value that is likely to be - // effectively the same as 0 when the low bits are masked. - if (hash == 0) - hash = 0x40000000; +private: + static inline UChar defaultCoverter(UChar ch) + { + return ch; + } + + static inline UChar defaultCoverter(char ch) + { + return static_cast<unsigned char>(ch); + } + + inline void addCharactersToHash(UChar a, UChar b) + { + m_hash += a; + unsigned tmp = (b << 11) ^ m_hash; + m_hash = (m_hash << 16) ^ tmp; + m_hash += m_hash >> 11; + } - return hash; -} + unsigned m_hash; + bool m_hasPendingCharacter; + UChar m_pendingCharacter; +}; } // namespace WTF diff --git a/JavaScriptCore/wtf/ThreadingPthreads.cpp b/JavaScriptCore/wtf/ThreadingPthreads.cpp index 98286d3..0017a6f 100644 --- a/JavaScriptCore/wtf/ThreadingPthreads.cpp +++ b/JavaScriptCore/wtf/ThreadingPthreads.cpp @@ -241,12 +241,6 @@ ThreadIdentifier currentThread() Mutex::Mutex() { -#if PTHREAD_MUTEX_NORMAL == PTHREAD_MUTEX_DEFAULT - - pthread_mutex_init(&m_mutex, 0); - -#else - pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); @@ -254,8 +248,6 @@ Mutex::Mutex() pthread_mutex_init(&m_mutex, &attr); pthread_mutexattr_destroy(&attr); - -#endif } Mutex::~Mutex() diff --git a/JavaScriptCore/wtf/gobject/GOwnPtr.cpp b/JavaScriptCore/wtf/gobject/GOwnPtr.cpp index da0d839..8dcfb9e 100644 --- a/JavaScriptCore/wtf/gobject/GOwnPtr.cpp +++ b/JavaScriptCore/wtf/gobject/GOwnPtr.cpp @@ -19,6 +19,8 @@ #include "config.h" #include "GOwnPtr.h" +#if ENABLE(GLIB_SUPPORT) + #include <gio/gio.h> #include <glib.h> @@ -65,3 +67,5 @@ template <> void freeOwnedGPtr<GFile>(GFile* ptr) g_object_unref(ptr); } } // namespace WTF + +#endif // ENABLE(GLIB_SUPPORT) diff --git a/JavaScriptCore/wtf/gobject/GOwnPtr.h b/JavaScriptCore/wtf/gobject/GOwnPtr.h index e04ee9d..cec3e43 100644 --- a/JavaScriptCore/wtf/gobject/GOwnPtr.h +++ b/JavaScriptCore/wtf/gobject/GOwnPtr.h @@ -22,6 +22,8 @@ #ifndef GOwnPtr_h #define GOwnPtr_h +#if ENABLE(GLIB_SUPPORT) + #include <algorithm> #include <wtf/Assertions.h> #include <wtf/Noncopyable.h> @@ -135,4 +137,7 @@ template <typename T> inline void freeOwnedGPtr(T* ptr) using WTF::GOwnPtr; +#endif // ENABLE(GLIB_SUPPORT) + #endif // GOwnPtr_h + diff --git a/JavaScriptCore/wtf/gobject/GRefPtr.cpp b/JavaScriptCore/wtf/gobject/GRefPtr.cpp index 14f7cf4..085684e 100644 --- a/JavaScriptCore/wtf/gobject/GRefPtr.cpp +++ b/JavaScriptCore/wtf/gobject/GRefPtr.cpp @@ -19,6 +19,8 @@ #include "config.h" #include "GRefPtr.h" +#if ENABLE(GLIB_SUPPORT) + #include <glib.h> namespace WTF { @@ -80,3 +82,5 @@ template <> void derefPlatformPtr(GSource* ptr) } } // namespace WTF + +#endif // ENABLE(GLIB_SUPPORT) diff --git a/JavaScriptCore/wtf/gobject/GRefPtr.h b/JavaScriptCore/wtf/gobject/GRefPtr.h index ede0a7a..4efd9be 100644 --- a/JavaScriptCore/wtf/gobject/GRefPtr.h +++ b/JavaScriptCore/wtf/gobject/GRefPtr.h @@ -23,6 +23,8 @@ #ifndef WTF_GRefPtr_h #define WTF_GRefPtr_h +#if ENABLE(GLIB_SUPPORT) + #include "AlwaysInline.h" #include "PlatformRefPtr.h" #include <algorithm> @@ -54,4 +56,6 @@ template <typename T> inline void derefPlatformPtr(T* ptr) } // namespace WTF +#endif // ENABLE(GLIB_SUPPORT) + #endif // WTF_GRefPtr_h diff --git a/JavaScriptCore/wtf/text/AtomicString.cpp b/JavaScriptCore/wtf/text/AtomicString.cpp index 1981170..c8140d6 100644 --- a/JavaScriptCore/wtf/text/AtomicString.cpp +++ b/JavaScriptCore/wtf/text/AtomicString.cpp @@ -156,6 +156,11 @@ static inline bool equal(StringImpl* string, const UChar* characters, unsigned l #endif } +bool operator==(const AtomicString& string, const Vector<UChar>& vector) +{ + return string.impl() && equal(string.impl(), vector.data(), vector.size()); +} + struct UCharBufferTranslator { static unsigned hash(const UCharBuffer& buf) { diff --git a/JavaScriptCore/wtf/text/AtomicString.h b/JavaScriptCore/wtf/text/AtomicString.h index cfabde7..06e63f4 100644 --- a/JavaScriptCore/wtf/text/AtomicString.h +++ b/JavaScriptCore/wtf/text/AtomicString.h @@ -126,15 +126,19 @@ private: inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); } bool operator==(const AtomicString& a, const char* b); +bool operator==(const AtomicString& a, const Vector<UChar>& b); inline bool operator==(const AtomicString& a, const String& b) { return equal(a.impl(), b.impl()); } inline bool operator==(const char* a, const AtomicString& b) { return b == a; } inline bool operator==(const String& a, const AtomicString& b) { return equal(a.impl(), b.impl()); } +inline bool operator==(const Vector<UChar>& a, const AtomicString& b) { return b == a; } inline bool operator!=(const AtomicString& a, const AtomicString& b) { return a.impl() != b.impl(); } inline bool operator!=(const AtomicString& a, const char *b) { return !(a == b); } inline bool operator!=(const AtomicString& a, const String& b) { return !equal(a.impl(), b.impl()); } +inline bool operator!=(const AtomicString& a, const Vector<UChar>& b) { return !(a == b); } inline bool operator!=(const char* a, const AtomicString& b) { return !(b == a); } inline bool operator!=(const String& a, const AtomicString& b) { return !equal(a.impl(), b.impl()); } +inline bool operator!=(const Vector<UChar>& a, const AtomicString& b) { return !(a == b); } inline bool equalIgnoringCase(const AtomicString& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); } inline bool equalIgnoringCase(const AtomicString& a, const char* b) { return equalIgnoringCase(a.impl(), b); } diff --git a/JavaScriptCore/wtf/text/StringImpl.h b/JavaScriptCore/wtf/text/StringImpl.h index cec0b80..7025d9f 100644 --- a/JavaScriptCore/wtf/text/StringImpl.h +++ b/JavaScriptCore/wtf/text/StringImpl.h @@ -233,9 +233,9 @@ public: unsigned hash() const { if (!m_hash) m_hash = computeHash(m_data, m_length); return m_hash; } unsigned existingHash() const { ASSERT(m_hash); return m_hash; } - static unsigned computeHash(const UChar* data, unsigned length) { return WTF::stringHash(data, length); } - static unsigned computeHash(const char* data, unsigned length) { return WTF::stringHash(data, length); } - static unsigned computeHash(const char* data) { return WTF::stringHash(data); } + static unsigned computeHash(const UChar* data, unsigned length) { return WTF::StringHasher::createHash<UChar>(data, length); } + static unsigned computeHash(const char* data, unsigned length) { return WTF::StringHasher::createHash<char>(data, length); } + static unsigned computeHash(const char* data) { return WTF::StringHasher::createHash<char>(data); } ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic))) delete this; } ALWAYS_INLINE bool hasOneRef() const { return (m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic)) == s_refCountIncrement; } diff --git a/JavaScriptCore/wtf/unicode/UTF8.cpp b/JavaScriptCore/wtf/unicode/UTF8.cpp index 21d5856..40c5609 100644 --- a/JavaScriptCore/wtf/unicode/UTF8.cpp +++ b/JavaScriptCore/wtf/unicode/UTF8.cpp @@ -240,7 +240,7 @@ ConversionResult convertUTF8ToUTF16( UChar* target = *targetStart; while (source < sourceEnd) { UChar32 ch = 0; - int extraBytesToRead = UTF8SequenceLength(*source) - 1; + int extraBytesToRead = inlineUTF8SequenceLength(*source) - 1; if (source + extraBytesToRead >= sourceEnd) { result = sourceExhausted; break; diff --git a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h index c9e2e1c..547ed32 100644 --- a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h +++ b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h @@ -58,7 +58,7 @@ namespace QUnicodeTables { QT_END_NAMESPACE // ugly hack to make UChar compatible with JSChar in API/JSStringRef.h -#if defined(Q_OS_WIN) || COMPILER(WINSCW) || (COMPILER(RVCT) && OS(SYMBIAN)) +#if defined(Q_OS_WIN) || COMPILER(WINSCW) || (COMPILER(RVCT) && !OS(LINUX)) typedef wchar_t UChar; #else typedef uint16_t UChar; diff --git a/JavaScriptCore/yarr/RegexInterpreter.cpp b/JavaScriptCore/yarr/RegexInterpreter.cpp index d50c6c8..17ffd8f 100644 --- a/JavaScriptCore/yarr/RegexInterpreter.cpp +++ b/JavaScriptCore/yarr/RegexInterpreter.cpp @@ -1106,6 +1106,10 @@ public: input.next(); context->matchBegin = input.getPos(); + + if (currentTerm().alternative.onceThrough) + context->term += currentTerm().alternative.next; + MATCH_NEXT(); } case ByteTerm::TypeBodyAlternativeEnd: @@ -1257,7 +1261,7 @@ public: PassOwnPtr<BytecodePattern> compile(BumpPointerAllocator* allocator) { - regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize); + regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize, m_pattern.m_body->m_alternatives[0]->onceThrough()); emitDisjunction(m_pattern.m_body); regexEnd(); @@ -1462,10 +1466,10 @@ public: } } - void regexBegin(unsigned numSubpatterns, unsigned callFrameSize) + void regexBegin(unsigned numSubpatterns, unsigned callFrameSize, bool onceThrough) { m_bodyDisjunction = adoptPtr(new ByteDisjunction(numSubpatterns, callFrameSize)); - m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin()); + m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin(onceThrough)); m_bodyDisjunction->terms[0].frameLocation = 0; m_currentAlternativeIndex = 0; } @@ -1475,11 +1479,11 @@ public: closeBodyAlternative(); } - void alternativeBodyDisjunction() + void alternativeBodyDisjunction(bool onceThrough) { int newAlternativeIndex = m_bodyDisjunction->terms.size(); m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex; - m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction()); + m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction(onceThrough)); m_currentAlternativeIndex = newAlternativeIndex; } @@ -1498,14 +1502,15 @@ public: for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { unsigned currentCountAlreadyChecked = inputCountAlreadyChecked; + PatternAlternative* alternative = disjunction->m_alternatives[alt]; + if (alt) { if (disjunction == m_pattern.m_body) - alternativeBodyDisjunction(); + alternativeBodyDisjunction(alternative->onceThrough()); else alternativeDisjunction(); } - PatternAlternative* alternative = disjunction->m_alternatives[alt]; unsigned minimumSize = alternative->m_minimumSize; ASSERT(minimumSize >= parenthesesInputCountAlreadyChecked); diff --git a/JavaScriptCore/yarr/RegexInterpreter.h b/JavaScriptCore/yarr/RegexInterpreter.h index 4da9cc5..37f17fe 100644 --- a/JavaScriptCore/yarr/RegexInterpreter.h +++ b/JavaScriptCore/yarr/RegexInterpreter.h @@ -94,6 +94,7 @@ struct ByteTerm { struct { int next; int end; + bool onceThrough; } alternative; unsigned checkInputCount; }; @@ -215,19 +216,21 @@ struct ByteTerm { return ByteTerm(TypeBackReference, subpatternId, false, inputPos); } - static ByteTerm BodyAlternativeBegin() + static ByteTerm BodyAlternativeBegin(bool onceThrough) { ByteTerm term(TypeBodyAlternativeBegin); term.alternative.next = 0; term.alternative.end = 0; + term.alternative.onceThrough = onceThrough; return term; } - static ByteTerm BodyAlternativeDisjunction() + static ByteTerm BodyAlternativeDisjunction(bool onceThrough) { ByteTerm term(TypeBodyAlternativeDisjunction); term.alternative.next = 0; term.alternative.end = 0; + term.alternative.onceThrough = onceThrough; return term; } @@ -236,6 +239,7 @@ struct ByteTerm { ByteTerm term(TypeBodyAlternativeEnd); term.alternative.next = 0; term.alternative.end = 0; + term.alternative.onceThrough = false; return term; } @@ -244,6 +248,7 @@ struct ByteTerm { ByteTerm term(TypeAlternativeBegin); term.alternative.next = 0; term.alternative.end = 0; + term.alternative.onceThrough = false; return term; } @@ -252,6 +257,7 @@ struct ByteTerm { ByteTerm term(TypeAlternativeDisjunction); term.alternative.next = 0; term.alternative.end = 0; + term.alternative.onceThrough = false; return term; } @@ -260,6 +266,7 @@ struct ByteTerm { ByteTerm term(TypeAlternativeEnd); term.alternative.next = 0; term.alternative.end = 0; + term.alternative.onceThrough = false; return term; } diff --git a/JavaScriptCore/yarr/RegexJIT.cpp b/JavaScriptCore/yarr/RegexJIT.cpp index 8740130..1b80464 100644 --- a/JavaScriptCore/yarr/RegexJIT.cpp +++ b/JavaScriptCore/yarr/RegexJIT.cpp @@ -986,10 +986,8 @@ class RegexGenerator : private MacroAssembler { parenthesesState.plantJumpToBacktrackIfExists(this); // A failure WITHIN the parens jumps here parenthesesState.linkAlternativeBacktracks(this); - if (term.invertOrCapture) { + if (term.invertOrCapture) store32(Imm32(-1), Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); - store32(Imm32(-1), Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); - } if (term.quantityType == QuantifierGreedy) storeToFrame(Imm32(0), parenthesesFrameLocation); @@ -1271,64 +1269,75 @@ class RegexGenerator : private MacroAssembler { // if there are any more alternatives, plant the check for input before looping. if (state.alternativeValid()) { PatternAlternative* nextAlternative = state.alternative(); - bool setAlternativeLoopLabel = false; if (!setRepeatAlternativeLabels && !nextAlternative->onceThrough()) { // We have handled non-repeating alternatives, jump to next iteration // and loop over repeating alternatives. state.jumpToBacktrack(jump(), this); - - firstAlternative = Label(this); - setRepeatAlternativeLabels = true; - setAlternativeLoopLabel = true; - } - - int countToCheckForNextAlternative = nextAlternative->m_minimumSize; - - if (countCheckedForCurrentAlternative > countToCheckForNextAlternative) { // CASE 1: current alternative was longer than the next one. - // If we get here, there the last input checked failed. - notEnoughInputForPreviousAlternative.link(this); - - // Check if sufficent input available to run the next alternative - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); - // We are now in the correct state to enter the next alternative; this add is only required - // to mirror and revert operation of the sub32, just below. - add32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); - - // If we get here, there the last input checked passed. - state.linkAlternativeBacktracks(this); - // No need to check if we can run the next alternative, since it is shorter - - // just update index. - sub32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); - } else if (countCheckedForCurrentAlternative < countToCheckForNextAlternative) { // CASE 2: next alternative is longer than the current one. + + countToCheckForFirstAlternative = nextAlternative->m_minimumSize; + // If we get here, there the last input checked failed. - // If there is insufficient input to run the current alternative, and the next alternative is longer, - // then there is definitely not enough input to run it - don't even check. Just adjust index, as if - // we had checked. notEnoughInputForPreviousAlternative.link(this); - add32(Imm32(countToCheckForNextAlternative - countCheckedForCurrentAlternative), index); - notEnoughInputForPreviousAlternative.append(jump()); - - // The next alternative is longer than the current one; check the difference. - state.linkAlternativeBacktracks(this); - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); - } else { // CASE 3: Both alternatives are the same length. - ASSERT(countCheckedForCurrentAlternative == countToCheckForNextAlternative); - - // If the next alterative is the same length as this one, then no need to check the input - - // if there was sufficent input to run the current alternative then there is sufficient - // input to run the next one; if not, there isn't. + state.linkAlternativeBacktracks(this); - } - if (setAlternativeLoopLabel) { + // Back up to start the looping alternatives. + if (countCheckedForCurrentAlternative) + sub32(Imm32(countCheckedForCurrentAlternative), index); + + firstAlternative = Label(this); + + state.checkedTotal = countToCheckForFirstAlternative; + if (countToCheckForFirstAlternative) + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); + + countCheckedForCurrentAlternative = countToCheckForFirstAlternative; + firstAlternativeInputChecked = Label(this); - countToCheckForFirstAlternative = countToCheckForNextAlternative; - setAlternativeLoopLabel = true; + + setRepeatAlternativeLabels = true; + } else { + int countToCheckForNextAlternative = nextAlternative->m_minimumSize; + + if (countCheckedForCurrentAlternative > countToCheckForNextAlternative) { // CASE 1: current alternative was longer than the next one. + // If we get here, then the last input checked failed. + notEnoughInputForPreviousAlternative.link(this); + + // Check if sufficent input available to run the next alternative + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); + // We are now in the correct state to enter the next alternative; this add is only required + // to mirror and revert operation of the sub32, just below. + add32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); + + // If we get here, then the last input checked passed. + state.linkAlternativeBacktracks(this); + // No need to check if we can run the next alternative, since it is shorter - + // just update index. + sub32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); + } else if (countCheckedForCurrentAlternative < countToCheckForNextAlternative) { // CASE 2: next alternative is longer than the current one. + // If we get here, then the last input checked failed. + // If there is insufficient input to run the current alternative, and the next alternative is longer, + // then there is definitely not enough input to run it - don't even check. Just adjust index, as if + // we had checked. + notEnoughInputForPreviousAlternative.link(this); + add32(Imm32(countToCheckForNextAlternative - countCheckedForCurrentAlternative), index); + notEnoughInputForPreviousAlternative.append(jump()); + + // The next alternative is longer than the current one; check the difference. + state.linkAlternativeBacktracks(this); + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); + } else { // CASE 3: Both alternatives are the same length. + ASSERT(countCheckedForCurrentAlternative == countToCheckForNextAlternative); + + // If the next alterative is the same length as this one, then no need to check the input - + // if there was sufficent input to run the current alternative then there is sufficient + // input to run the next one; if not, there isn't. + state.linkAlternativeBacktracks(this); + } + state.checkedTotal -= countCheckedForCurrentAlternative; + countCheckedForCurrentAlternative = countToCheckForNextAlternative; + state.checkedTotal += countCheckedForCurrentAlternative; } - - state.checkedTotal -= countCheckedForCurrentAlternative; - countCheckedForCurrentAlternative = countToCheckForNextAlternative; - state.checkedTotal += countCheckedForCurrentAlternative; } } |