diff options
author | Russell Brenner <russellbrenner@google.com> | 2010-11-18 17:33:13 -0800 |
---|---|---|
committer | Russell Brenner <russellbrenner@google.com> | 2010-12-02 13:47:21 -0800 |
commit | 6b70adc33054f8aee8c54d0f460458a9df11b8a5 (patch) | |
tree | 103a13998c33944d6ab3b8318c509a037e639460 /JavaScriptCore | |
parent | bdf4ebc8e70b2d221b6ee7a65660918ecb1d33aa (diff) | |
download | external_webkit-6b70adc33054f8aee8c54d0f460458a9df11b8a5.zip external_webkit-6b70adc33054f8aee8c54d0f460458a9df11b8a5.tar.gz external_webkit-6b70adc33054f8aee8c54d0f460458a9df11b8a5.tar.bz2 |
Merge WebKit at r72274: Initial merge by git.
Change-Id: Ie51f0b4a16da82942bd516dce59cfb79ebbe25fb
Diffstat (limited to 'JavaScriptCore')
55 files changed, 2182 insertions, 551 deletions
diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index 8f663ff..bf45cd8 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,755 @@ +2010-11-17 Sam Weinig <sam@webkit.org> + + Reviewed by Anders Carlsson. + + Add stubbed out ScrollAnimator for the Mac + https://bugs.webkit.org/show_bug.cgi?id=49678 + + * wtf/Platform.h: Enable SMOOTH_SCROLLING on the Mac, this has no + change in behavior at the moment. + +2010-11-17 David Kilzer <ddkilzer@apple.com> + + <http://webkit.org/b/49634> Make overflow guards in WTF::String::utf8 explicit + + Reviewed by Darin Adler. + + Add an explicit overflow check prior to allocating our buffer, + rather than implicitly relying on the guard in convertUTF16ToUTF8. + + * wtf/text/WTFString.cpp: + (WTF::String::utf8): + +2010-11-17 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r72197. + http://trac.webkit.org/changeset/72197 + https://bugs.webkit.org/show_bug.cgi?id=49661 + + broke fast/regex/test1.html (Requested by stampho on #webkit). + + * runtime/JSGlobalData.h: + * runtime/RegExp.cpp: + (JSC::RegExpRepresentation::~RegExpRepresentation): + (JSC::RegExp::compile): + (JSC::RegExp::match): + * tests/mozilla/expected.html: + * wtf/Platform.h: + * yarr/RegexCompiler.cpp: + * yarr/RegexCompiler.h: + * yarr/RegexInterpreter.cpp: + * yarr/RegexInterpreter.h: + * yarr/RegexJIT.cpp: + (JSC::Yarr::jitCompileRegex): + * yarr/RegexJIT.h: + (JSC::Yarr::RegexCodeBlock::RegexCodeBlock): + (JSC::Yarr::RegexCodeBlock::~RegexCodeBlock): + (JSC::Yarr::RegexCodeBlock::getFallback): + (JSC::Yarr::RegexCodeBlock::setFallback): + (JSC::Yarr::executeRegex): + * yarr/RegexParser.h: + * yarr/RegexPattern.h: + +2010-11-17 Peter Varga <pvarga@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + YARR JIT should fallback to YARR Interpreter instead of PCRE. + https://bugs.webkit.org/show_bug.cgi?id=46719 + + Remove the ENABLE_YARR macro and the option of matching regular + expressions with PCRE from JavaScriptCore. + + * runtime/JSGlobalData.h: + * runtime/RegExp.cpp: + (JSC::RegExp::compile): + (JSC::RegExp::match): + * tests/mozilla/expected.html: + * wtf/Platform.h: + * yarr/RegexCompiler.cpp: + * yarr/RegexCompiler.h: + * yarr/RegexInterpreter.cpp: + (JSC::Yarr::byteCompileRegex): + * yarr/RegexInterpreter.h: + * yarr/RegexJIT.cpp: + (JSC::Yarr::jitCompileRegex): + * yarr/RegexJIT.h: + (JSC::Yarr::RegexCodeBlock::RegexCodeBlock): + (JSC::Yarr::RegexCodeBlock::~RegexCodeBlock): + (JSC::Yarr::RegexCodeBlock::getFallback): + (JSC::Yarr::RegexCodeBlock::isFallback): + (JSC::Yarr::RegexCodeBlock::setFallback): + (JSC::Yarr::executeRegex): + * yarr/RegexParser.h: + * yarr/RegexPattern.h: + +2010-11-17 Peter Varga <pvarga@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Extend YARR Interpreter with beginning character look-up optimization + https://bugs.webkit.org/show_bug.cgi?id=45751 + + Add beginning character look-up optimization which sets the start + index to the first possible successful pattern match. + Extend YARR Interpreter with lookupForBeginChars function which + implements the beginning character look-up optimization. + + * yarr/RegexInterpreter.cpp: + (JSC::Yarr::Interpreter::InputStream::readPair): + (JSC::Yarr::Interpreter::InputStream::isNotAvailableInput): + (JSC::Yarr::Interpreter::lookupForBeginChars): + (JSC::Yarr::Interpreter::matchDisjunction): + (JSC::Yarr::Interpreter::interpret): + * yarr/RegexInterpreter.h: + (JSC::Yarr::BytecodePattern::BytecodePattern): + +2010-11-17 Alexis Menard <alexis.menard@nokia.com>, Simon Hausmann <simon.hausmann@nokia.com> + + Reviewed by Kenneth Christiansen, Tor Arne Vestbø. + + [Qt] Add support for use GStreamer with the Qt build + + Enable the build/inclusion of the wtf/QObject convenience classes. + + * JavaScriptCore.pri: + * wtf/wtf.pri: + +2010-11-17 Peter Varga <pvarga@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Collect the beginning characters in a RegExp pattern for look-up + optimization + https://bugs.webkit.org/show_bug.cgi?id=45748 + + Extend the YARR's parser with an algorithm which collects the potential + beginning characters from a RegExp pattern for later look-up optimization. + + * yarr/RegexCompiler.cpp: + (JSC::Yarr::BeginCharHelper::BeginCharHelper): + (JSC::Yarr::BeginCharHelper::addBeginChar): + (JSC::Yarr::BeginCharHelper::merge): + (JSC::Yarr::BeginCharHelper::addCharacter): + (JSC::Yarr::BeginCharHelper::linkHotTerms): + (JSC::Yarr::RegexPatternConstructor::RegexPatternConstructor): + (JSC::Yarr::RegexPatternConstructor::addBeginTerm): + (JSC::Yarr::RegexPatternConstructor::setupDisjunctionBeginTerms): + (JSC::Yarr::RegexPatternConstructor::setupAlternativeBeginTerms): + (JSC::Yarr::RegexPatternConstructor::setupBeginChars): + (JSC::Yarr::compileRegex): + * yarr/RegexPattern.h: + (JSC::Yarr::TermChain::TermChain): + (JSC::Yarr::BeginChar::BeginChar): + (JSC::Yarr::RegexPattern::RegexPattern): + (JSC::Yarr::RegexPattern::reset): + +2010-11-17 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r72160. + http://trac.webkit.org/changeset/72160 + https://bugs.webkit.org/show_bug.cgi?id=49646 + + Broke lots of fast/profiler tests, among others (Requested by + aroben on #webkit). + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + (JSC::CodeBlock::functionRegisterForBytecodeOffset): + (JSC::CodeBlock::shrinkToFit): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::addFunctionRegisterInfo): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitCallVarargs): + (JSC::BytecodeGenerator::emitReturn): + (JSC::BytecodeGenerator::emitConstruct): + * bytecompiler/BytecodeGenerator.h: + (JSC::CallArguments::profileHookRegister): + * bytecompiler/NodesCodegen.cpp: + (JSC::CallArguments::CallArguments): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::unwindCallFrame): + (JSC::Interpreter::throwException): + (JSC::Interpreter::execute): + (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_profile_will_call): + (JSC::JIT::emit_op_profile_did_call): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_profile_will_call): + (JSC::JIT::emit_op_profile_did_call): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * jit/JITStubs.h: + * profiler/Profile.cpp: + (JSC::Profile::Profile): + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::addParentForConsoleStart): + (JSC::ProfileGenerator::willExecute): + (JSC::ProfileGenerator::didExecute): + (JSC::ProfileGenerator::stopProfiling): + * profiler/ProfileGenerator.h: + * profiler/ProfileNode.cpp: + (JSC::ProfileNode::ProfileNode): + (JSC::ProfileNode::willExecute): + * profiler/ProfileNode.h: + (JSC::ProfileNode::create): + (JSC::ProfileNode::operator==): + * profiler/Profiler.cpp: + (JSC::dispatchFunctionToProfiles): + (JSC::Profiler::willExecute): + (JSC::Profiler::didExecute): + * profiler/Profiler.h: + +2010-11-16 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Sam Weinig. + + Bug 49635 - Profiler implementation is fragile + + The profile presently requires the exception handling mechanism to explicitly + remove all stack frames that are exited during the exception unwind mechanism. + This is fragile in a number of ways: + * We have to change bytecode register allocation when compiling code to run + when profiling, to preserve the callee function (this is also required to + call did_call after the call has returned). + * In the JIT we have to maintain additional data structures + (CodeBlock::RareData::m_functionRegisterInfos) to map back to the register + containing the callee. + * In the interpreter we use 'magic values' to offset into the instruction + stream to rediscover the register containing the function. + + Instead, move profiling into the head and tail of functions. + * This correctly accounts the cost of the call itself to the caller. + * This allows us to access the callee function object from the callframe. + * This means that at the point a call is made we can track the stack depth + on the ProfileNode. + * When unwinding we can simply report the depth at which the exception is + being handled - all call frames above this level are freed. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + (JSC::CodeBlock::shrinkToFit): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::bytecodeOffset): + (JSC::CodeBlock::methodCallLinkInfo): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitCallVarargs): + (JSC::BytecodeGenerator::emitReturn): + (JSC::BytecodeGenerator::emitConstruct): + * bytecompiler/BytecodeGenerator.h: + (JSC::CallArguments::count): + * bytecompiler/NodesCodegen.cpp: + (JSC::CallArguments::CallArguments): + * interpreter/Interpreter.cpp: + (JSC::ProfileHostCall::ProfileHostCall): + (JSC::ProfileHostCall::~ProfileHostCall): + (JSC::Interpreter::unwindCallFrame): + (JSC::Interpreter::throwException): + (JSC::Interpreter::execute): + (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_profile_has_called): + (JSC::JIT::emit_op_profile_will_return): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_profile_has_called): + (JSC::JIT::emit_op_profile_will_return): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * jit/JITStubs.h: + * profiler/Profile.cpp: + (JSC::Profile::Profile): + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::addParentForConsoleStart): + (JSC::ProfileGenerator::willExecute): + (JSC::ProfileGenerator::didExecute): + (JSC::ProfileGenerator::exceptionUnwind): + (JSC::ProfileGenerator::stopProfiling): + * profiler/ProfileGenerator.h: + * profiler/ProfileNode.cpp: + (JSC::ProfileNode::ProfileNode): + (JSC::ProfileNode::willExecute): + * profiler/ProfileNode.h: + (JSC::ProfileNode::create): + (JSC::ProfileNode::operator==): + (JSC::ProfileNode::exec): + * profiler/Profiler.cpp: + (JSC::dispatchFunctionToProfiles): + (JSC::Profiler::hasCalled): + (JSC::Profiler::willEvaluate): + (JSC::Profiler::willReturn): + (JSC::Profiler::didEvaluate): + (JSC::Profiler::exceptionUnwind): + * profiler/Profiler.h: + +2010-11-16 Brian Weinstein <bweinstein@apple.com> + + Reviewed by Adam Roben and Steve Falkenburg. + + Touch Platform.h to force a rebuild for Windows. + + * wtf/Platform.h: + +2010-11-16 Steve Falkenburg <sfalken@apple.com> + + Reviewed by Adam Roben. + + Disable LTCG for Windows Release builds. Add new Release_LTCG configuration. + https://bugs.webkit.org/show_bug.cgi?id=49632 + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * JavaScriptCore.vcproj/jsc/jsc.vcproj: + * JavaScriptCore.vcproj/testapi/testapi.vcproj: + +2010-11-16 Peter Varga <pvarga@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + The number of recursive match calls isn't limited in YARR Interpreter + https://bugs.webkit.org/show_bug.cgi?id=47906 + + Check the number of the matchDisjunction recursive calls to avoid unbounded + recursion. + Now the matchDisjunction function returns JSRegExpResult instead of bool. + The JSRegExpResult enum contains the result of matching or the error code + of the failure (like HitLimit) which terminates the matching. + The error codes are based on pcre's jsRegExpExecute error codes. + + * yarr/RegexInterpreter.cpp: + (JSC::Yarr::Interpreter::parenthesesDoBacktrack): + (JSC::Yarr::Interpreter::matchParentheses): + (JSC::Yarr::Interpreter::backtrackParentheses): + (JSC::Yarr::Interpreter::matchDisjunction): + (JSC::Yarr::Interpreter::matchNonZeroDisjunction): + (JSC::Yarr::Interpreter::interpret): + (JSC::Yarr::Interpreter::Interpreter): + * yarr/RegexInterpreter.h: + +2010-11-16 Brian Weinstein <bweinstein@apple.com> + + Rest of the Windows build fix. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2010-11-16 Gavin Barraclough <barraclough@apple.com> + + Windows build fix pt 1. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2010-11-16 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=49606 + + The bug here is that we read the prototype from the RHS argument using a regular + op_get_by_id before op_instanceof has checked that this is an object implementing + HasInstance. This incorrect behaviour gives rise to further unnecessary complexity + in the code base, since we have additional logic (implemented using the + GetByIdExceptionInfo data structures on CodeBlock) to convert not an object errors + from the get_by_id into invalid parameter errors. Having fixed this bug this code + is all redundant, since in these cases the get_by_id will never have been reached. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + (JSC::CodeBlock::shrinkToFit): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::addExpressionInfo): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitCheckHasInstance): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::InstanceOfNode::emitBytecode): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::throwException): + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_check_has_instance): + (JSC::JIT::emit_op_instanceof): + (JSC::JIT::emitSlow_op_check_has_instance): + (JSC::JIT::emitSlow_op_instanceof): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_check_has_instance): + (JSC::JIT::emit_op_instanceof): + (JSC::JIT::emitSlow_op_check_has_instance): + (JSC::JIT::emitSlow_op_instanceof): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * jit/JITStubs.h: + * runtime/ExceptionHelpers.cpp: + (JSC::createInterruptedExecutionException): + (JSC::createTerminatedExecutionException): + (JSC::createUndefinedVariableError): + (JSC::createNotAFunctionError): + (JSC::createNotAnObjectError): + * runtime/ExceptionHelpers.h: + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + * runtime/JSGlobalData.h: + * runtime/JSNotAnObject.cpp: + (JSC::JSNotAnObject::toPrimitive): + (JSC::JSNotAnObject::getPrimitiveNumber): + (JSC::JSNotAnObject::toBoolean): + (JSC::JSNotAnObject::toNumber): + (JSC::JSNotAnObject::toString): + (JSC::JSNotAnObject::toObject): + (JSC::JSNotAnObject::getOwnPropertySlot): + (JSC::JSNotAnObject::getOwnPropertyDescriptor): + (JSC::JSNotAnObject::put): + (JSC::JSNotAnObject::deleteProperty): + (JSC::JSNotAnObject::getOwnPropertyNames): + * runtime/JSNotAnObject.h: + (JSC::JSNotAnObject::JSNotAnObject): + * runtime/JSObject.h: + (JSC::JSObject::isActivationObject): + * runtime/JSValue.cpp: + (JSC::JSValue::toObjectSlowCase): + (JSC::JSValue::synthesizeObject): + (JSC::JSValue::synthesizePrototype): + +2010-11-15 Darin Adler <darin@apple.com> + + Reviewed by Sam Weinig. + + Harden additional string functions against large lengths + https://bugs.webkit.org/show_bug.cgi?id=49574 + + * wtf/text/CString.cpp: + (WTF::CString::init): Check for length that is too large for CString. + (WTF::CString::newUninitialized): Ditto. + (WTF::CString::copyBufferIfNeeded): Fix types so the length stays + in a size_t. + + * wtf/text/WTFString.cpp: + (WTF::String::append): Check for length that is too large. + +2010-11-15 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Sam Weinig. + + Bug 49577 - Function.prototype should be non-configurable + + JSC lazily allocates the prototype property of Function objects. + + We check the prototype exists on 'get', but not on 'put'. + If you 'put' without having first done a 'get' you can end up with a configurable + prototype (prototype should only ever be non-configurable). + + This is visible in a couple of ways: + * 'delete' on the property may succeed. (the next access will result in a new, + reset prototype object). + * the prototype may be set to a getter. + + * runtime/JSFunction.cpp: + (JSC::JSFunction::getOwnPropertyNames): + Reify the prototype property before allowing an enumerate including don't enum properties. + (JSC::JSFunction::put): + Reify the prototype property before any put to it. + +2010-11-15 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Geoff Garen. + + Bug 49488 - Only add source specific information to exceptions in Interpreter::throwException + + Three types of source location information are added to errors. + + (1) Divot information. + + This was added with the intention of using it to provide better source highlighting in the inspector. + We may still want to do so, but we probably should not be exposing these values in a manner visible to + user scripts – only through an internal C++ interface. The code adding divot properties to objects has + been removed. + + (2) Line number information. + + Line number information is presently sometimes added at the point the exception is created, and sometimes + added at the point the exception passes through throwException. Change this so that throwException has + the sole responsibility for adding line number and source file information. + + (3) Source snippets in the message of certain type errors (e.g. 'doc' in `Result of expression 'doc' [undefined] is not an object.`). + + These messages are currently created at the point the exceptions is raised. Instead reformat the message + such that the source snippet is located at the end (`Result of expression 'b1' [undefined] is not an object.` + becomes `'undefined' is not an object (evaluating 'b1.property')`), and append these to the message at + the in throw Exception. This presents a number of advantages: + * we no longer need to have source location information to create these TypeErrors. + * we can chose to append source location information in other error messages, including those where + passing source location to the point of construction would be inconvenient. + * we can chose in future to omit to append source location information when running in a non-debug mode. + + This also cleans up some error output, e.g. removing double brackets ('[[]]') around objects in output, + removing double periods (..) at end of lines, and adding slightly more context to some errors. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::expressionRangeForBytecodeOffset): + - Separated called to access line and range information. + + * bytecode/CodeBlock.h: + - Separated called to access line and range information. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::resolve): + (JSC::Interpreter::resolveSkip): + (JSC::Interpreter::resolveGlobal): + (JSC::Interpreter::resolveGlobalDynamic): + (JSC::Interpreter::resolveBaseAndProperty): + (JSC::isInvalidParamForIn): + (JSC::isInvalidParamForInstanceOf): + - Update parameters passed to error constructors. + (JSC::appendSourceToError): + - Update message property to add location information (previously added in createErrorMessage, in ExceptionHelpers) + (JSC::Interpreter::throwException): + - Updated to call appendSourceToError. + (JSC::Interpreter::privateExecute): + - Update parameters passed to error constructors. + + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + - Update parameters passed to error constructors. + + * runtime/Error.cpp: + (JSC::addErrorInfo): + (JSC::hasErrorInfo): + - Removed divot properties. + + * runtime/Error.h: + - Removed divot properties. + + * runtime/ErrorInstance.cpp: + (JSC::ErrorInstance::ErrorInstance): + - Initialize new property. + + * runtime/ErrorInstance.h: + (JSC::ErrorInstance::appendSourceToMessage): + (JSC::ErrorInstance::setAppendSourceToMessage): + (JSC::ErrorInstance::clearAppendSourceToMessage): + - Added flag to check for errors needing location information appending. + (JSC::ErrorInstance::isErrorInstance): + - Added virtual method to check for ErrorInstances. + + * runtime/ExceptionHelpers.cpp: + (JSC::createUndefinedVariableError): + (JSC::createInvalidParamError): + (JSC::createNotAConstructorError): + (JSC::createNotAFunctionError): + (JSC::createNotAnObjectError): + - Update parameters passed to error constructors, stopped adding line number information early, changed TypeError messages. + + * runtime/ExceptionHelpers.h: + - Updated function signatures. + + * runtime/JSFunction.cpp: + (JSC::callHostFunctionAsConstructor): + - Update parameters passed to error constructors. + + * runtime/JSObject.h: + (JSC::JSObject::isErrorInstance): + - Added virtual method to check for ErrorInstances. + +2010-11-12 Anders Carlsson <andersca@apple.com> + + Reviewed by Adam Roben. + + CString(const char*) crashes when passed a null pointer + https://bugs.webkit.org/show_bug.cgi?id=49450 + + * wtf/text/CString.cpp: + (WTF::CString::CString): + Return early if str is null. + +2010-11-11 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + Bug 49420 - Clean up syntax/reference error throw. + + Some errors detected at compile time are thrown at runtime. We currently do so using a op_new_error/op_throw bytecode pair. + This is not ideal. op_throw is used for explicit user throw statements, and has different requirements in terms or meta data + attached to the exception (controlled by the explicitThrow parameter passed to Interpreter::throwException). To work around + this, op_new_error has to add the meta data at an early stage, which is unlike other VM exceptions being raised. + + We can simplify this and bring into line with other exception behaviour by changing new_error from just allocating an + Exception instance to also throwing it – but as a regular VM throw, correctly passing explicitThrow as false. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + (JSC::CodeBlock::expressionRangeForBytecodeOffset): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitThrowReferenceError): + (JSC::BytecodeGenerator::emitThrowSyntaxError): + (JSC::BytecodeGenerator::emitThrowExpressionTooDeepException): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::emitNodeInConditionContext): + * bytecompiler/NodesCodegen.cpp: + (JSC::ThrowableExpressionData::emitThrowReferenceError): + (JSC::ThrowableExpressionData::emitThrowSyntaxError): + (JSC::RegExpNode::emitBytecode): + (JSC::PostfixErrorNode::emitBytecode): + (JSC::PrefixErrorNode::emitBytecode): + (JSC::AssignErrorNode::emitBytecode): + (JSC::ForInNode::emitBytecode): + (JSC::ContinueNode::emitBytecode): + (JSC::BreakNode::emitBytecode): + (JSC::ReturnNode::emitBytecode): + (JSC::LabelNode::emitBytecode): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_throw_reference_error): + (JSC::JIT::emit_op_throw_syntax_error): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_throw_reference_error): + (JSC::JIT::emit_op_throw_syntax_error): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * jit/JITStubs.h: + * parser/Nodes.h: + +2010-11-11 Darin Adler <darin@apple.com> + + Reviewed by Sam Weinig. + + Harden some string functions against large lengths + https://bugs.webkit.org/show_bug.cgi?id=49293 + + * wtf/text/StringImpl.cpp: + (WTF::StringImpl::create): Fix incorrect use of PassRefPtr. Check for + strlen results that are too large for StringImpl. + (WTF::StringImpl::lower): Check for lengths that are too large for + int32_t. + (WTF::StringImpl::upper): Fix incorrect use of PassRefPtr. Check for + lengths that are too large for int32_t. + (WTF::StringImpl::secure): Fix incorect use of PassRefPtr. Use unsigned + rather than int and int32_t so we can handle any length. + (WTF::StringImpl::foldCase): Fix incorrect use of PassRefPtr. Check for + lengths that are too large for int32_t. + (WTF::StringImpl::find): Check for strlen results that are too large for + StringImpl. + (WTF::StringImpl::findIgnoringCase): Ditto. + (WTF::StringImpl::replace): Fix incorrect use of PassRefPtr. + (WTF::StringImpl::createWithTerminatingNullCharacter): Check before + incrementing length. + +2010-11-11 Dan Horák <dan@danny.cz> + + Reviewed by Andreas Kling. + + Add support for the s390/s390x architectures, it's big-endian + with s390 being 32-bit and s390x being 64-bit. + + https://bugs.webkit.org/show_bug.cgi?id=34786 + + * wtf/Platform.h: + +2010-11-10 Csaba Osztrogonác <ossy@webkit.org> + + Reviewed by David Hyatt. + + HTML5 Ruby support should be mandatory feature + https://bugs.webkit.org/show_bug.cgi?id=49272 + + Remove Ruby as optional feature. + + * Configurations/FeatureDefines.xcconfig: + * JavaScriptCorePrefix.h:: Touch it to avoid incremental build failure on Windows. + +2010-11-10 Peter Rybin <peter.rybin@gmail.com> + + Reviewed by Adam Barth. + + HTML parser should provide script column position within HTML document to JavaScript engine + https://bugs.webkit.org/show_bug.cgi?id=45271 + + Adds TextPosition* classes -- a structure that stores line/column/generation + level coordinates inside text document. Adds *BasedNumber classes -- typesafe int + wrappers that emphasize whether int number is used as zero-based or + one-based. + + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.xcodeproj/project.pbxproj: + * wtf/text/TextPosition.h: Added. + (WTF::TextPosition::TextPosition): + (WTF::TextPosition::minimumPosition): + (WTF::TextPosition::belowRangePosition): + (WTF::ZeroBasedNumber::fromZeroBasedInt): + (WTF::ZeroBasedNumber::ZeroBasedNumber): + (WTF::ZeroBasedNumber::zeroBasedInt): + (WTF::ZeroBasedNumber::base): + (WTF::ZeroBasedNumber::belowBase): + (WTF::OneBasedNumber::fromOneBasedInt): + (WTF::OneBasedNumber::OneBasedNumber): + (WTF::OneBasedNumber::oneBasedInt): + (WTF::OneBasedNumber::convertAsZeroBasedInt): + (WTF::OneBasedNumber::convertToZeroBased): + (WTF::OneBasedNumber::base): + (WTF::OneBasedNumber::belowBase): + (WTF::toZeroBasedTextPosition): + (WTF::toOneBasedTextPosition): + (WTF::ZeroBasedNumber::convertToOneBased): + +2010-11-09 Gabor Loki <loki@webkit.org> + + Reviewed by Gavin Barraclough. + + ARM JIT asserts when loading http://reader.google.com in debug mode + https://bugs.webkit.org/show_bug.cgi?id=48912 + + There are several cases when the uninterrupted sequence is larger than + maximum required offset for pathing the same sequence. Eg.: if in a + uninterrupted sequence the last macroassembler's instruction is a stub + call, it emits store instruction(s) which should not be included in the + calculation of length of uninterrupted sequence. So, the insnSpace and + constSpace should be upper limit instead of hard limit. + + * jit/JIT.h: + * jit/JITInlineMethods.h: + (JSC::JIT::endUninterruptedSequence): + +2010-11-09 David Kilzer <ddkilzer@apple.com> + + <http://webkit.org/b/49279> Fix include statements for local headers + + Reviewed by Gavin Barraclough. + + Use "Foo.h" instead of <Foo.h> for local headers. + + * assembler/AbstractMacroAssembler.h: Also fixed sort order. + * assembler/CodeLocation.h: + * yarr/RegexJIT.h: + * yarr/RegexParser.h: + 2010-11-08 Adam Roben <aroben@apple.com> Roll out r71532 diff --git a/JavaScriptCore/Configurations/FeatureDefines.xcconfig b/JavaScriptCore/Configurations/FeatureDefines.xcconfig index d08fadf..46d5de4 100644 --- a/JavaScriptCore/Configurations/FeatureDefines.xcconfig +++ b/JavaScriptCore/Configurations/FeatureDefines.xcconfig @@ -91,9 +91,6 @@ ENABLE_NOTIFICATIONS = ; ENABLE_OFFLINE_WEB_APPLICATIONS = ENABLE_OFFLINE_WEB_APPLICATIONS; ENABLE_PROGRESS_TAG = ENABLE_PROGRESS_TAG; -ENABLE_RUBY = $(ENABLE_RUBY_$(REAL_PLATFORM_NAME)); -ENABLE_RUBY_macosx = ENABLE_RUBY; - ENABLE_SHARED_WORKERS = $(ENABLE_SHARED_WORKERS_$(REAL_PLATFORM_NAME)); ENABLE_SHARED_WORKERS_macosx = ENABLE_SHARED_WORKERS; @@ -124,4 +121,4 @@ ENABLE_XHTMLMP = ; ENABLE_XPATH = ENABLE_XPATH; ENABLE_XSLT = ENABLE_XSLT; -FEATURE_DEFINES = $(ENABLE_LINK_PREFETCH) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_3D_CANVAS) $(ENABLE_3D_RENDERING) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CLIENT_BASED_GEOLOCATION) $(ENABLE_DATABASE) $(ENABLE_DATAGRID) $(ENABLE_DATALIST) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_DOM_STORAGE) $(ENABLE_EVENTSOURCE) $(ENABLE_FILTERS) $(ENABLE_FILE_SYSTEM) $(ENABLE_FULLSCREEN_API) $(ENABLE_GEOLOCATION) $(ENABLE_ICONDATABASE) $(ENABLE_IMAGE_RESIZER) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_SPEECH) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_MATHML) $(ENABLE_METER_TAG) $(ENABLE_NOTIFICATIONS) $(ENABLE_OFFLINE_WEB_APPLICATIONS) $(ENABLE_PROGRESS_TAG) $(ENABLE_RUBY) $(ENABLE_SHARED_WORKERS) $(ENABLE_SVG) $(ENABLE_SVG_ANIMATION) $(ENABLE_SVG_AS_IMAGE) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_SVG_FOREIGN_OBJECT) $(ENABLE_SVG_USE) $(ENABLE_VIDEO) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WML) $(ENABLE_WORKERS) $(ENABLE_XHTMLMP) $(ENABLE_XPATH) $(ENABLE_XSLT); +FEATURE_DEFINES = $(ENABLE_LINK_PREFETCH) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_3D_CANVAS) $(ENABLE_3D_RENDERING) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CLIENT_BASED_GEOLOCATION) $(ENABLE_DATABASE) $(ENABLE_DATAGRID) $(ENABLE_DATALIST) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_DOM_STORAGE) $(ENABLE_EVENTSOURCE) $(ENABLE_FILTERS) $(ENABLE_FILE_SYSTEM) $(ENABLE_FULLSCREEN_API) $(ENABLE_GEOLOCATION) $(ENABLE_ICONDATABASE) $(ENABLE_IMAGE_RESIZER) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_SPEECH) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_MATHML) $(ENABLE_METER_TAG) $(ENABLE_NOTIFICATIONS) $(ENABLE_OFFLINE_WEB_APPLICATIONS) $(ENABLE_PROGRESS_TAG) $(ENABLE_SHARED_WORKERS) $(ENABLE_SVG) $(ENABLE_SVG_ANIMATION) $(ENABLE_SVG_AS_IMAGE) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_SVG_FOREIGN_OBJECT) $(ENABLE_SVG_USE) $(ENABLE_VIDEO) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WML) $(ENABLE_WORKERS) $(ENABLE_XHTMLMP) $(ENABLE_XPATH) $(ENABLE_XSLT); diff --git a/JavaScriptCore/Configurations/Version.xcconfig b/JavaScriptCore/Configurations/Version.xcconfig index 8cdcafc..d4cb8e7 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 = 12; +MINOR_VERSION = 13; TINY_VERSION = 0; FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION); diff --git a/JavaScriptCore/GNUmakefile.am b/JavaScriptCore/GNUmakefile.am index c507f5d..f7806b4 100644 --- a/JavaScriptCore/GNUmakefile.am +++ b/JavaScriptCore/GNUmakefile.am @@ -518,6 +518,7 @@ javascriptcore_sources += \ JavaScriptCore/wtf/text/StringImpl.cpp \ JavaScriptCore/wtf/text/StringImpl.h \ JavaScriptCore/wtf/text/StringStatics.cpp \ + JavaScriptCore/wtf/text/TextPosition.h \ JavaScriptCore/wtf/text/WTFString.cpp \ JavaScriptCore/wtf/text/WTFString.h \ JavaScriptCore/wtf/ThreadIdentifierDataPthreads.cpp \ diff --git a/JavaScriptCore/JavaScriptCore.gypi b/JavaScriptCore/JavaScriptCore.gypi index 6252d07..deb36fb 100644 --- a/JavaScriptCore/JavaScriptCore.gypi +++ b/JavaScriptCore/JavaScriptCore.gypi @@ -461,6 +461,7 @@ 'wtf/text/StringImpl.cpp', 'wtf/text/StringImpl.h', 'wtf/text/StringStatics.cpp', + 'wtf/text/TextPosition.h', 'wtf/text/WTFString.cpp', 'wtf/text/WTFString.h', 'wtf/unicode/Collator.h', diff --git a/JavaScriptCore/JavaScriptCore.pri b/JavaScriptCore/JavaScriptCore.pri index 847576d..0590b94 100644 --- a/JavaScriptCore/JavaScriptCore.pri +++ b/JavaScriptCore/JavaScriptCore.pri @@ -42,6 +42,7 @@ INCLUDEPATH = \ $$PWD/profiler \ $$PWD/runtime \ $$PWD/wtf \ + $$PWD/wtf/gobject \ $$PWD/wtf/symbian \ $$PWD/wtf/unicode \ $$PWD/yarr \ diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index aa9d529..449c0bb 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -88,7 +88,7 @@ EXPORTS ?createEmptyString@SmallStrings@JSC@@AAEXPAVJSGlobalData@2@@Z ?createError@JSC@@YAPAVJSObject@1@PAVExecState@1@ABVUString@1@@Z ?createInheritorID@JSObject@JSC@@AAEPAVStructure@2@XZ - ?createInterruptedExecutionException@JSC@@YA?AVJSValue@1@PAVJSGlobalData@1@@Z + ?createInterruptedExecutionException@JSC@@YAPAVJSObject@1@PAVJSGlobalData@1@@Z ?createLeaked@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@W4ThreadStackType@2@@Z ?createReferenceError@JSC@@YAPAVJSObject@1@PAVExecState@1@ABVUString@1@@Z ?createSingleCharacterString@SmallStrings@JSC@@AAEXPAVJSGlobalData@2@E@Z diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj index 4823286..8c83526 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -72,13 +72,15 @@ <Tool
Name="VCWebDeploymentTool"
/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
</Configuration>
<Configuration
Name="Release|Win32"
ConfigurationType="2"
InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\FeatureDefines.vsprops;$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\release.vsprops;.\JavaScriptCoreCommon.vsprops;.\JavaScriptCoreCF.vsprops"
CharacterSet="1"
- WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -131,6 +133,9 @@ <Tool
Name="VCWebDeploymentTool"
/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
</Configuration>
<Configuration
Name="Debug_Internal|Win32"
@@ -189,6 +194,9 @@ <Tool
Name="VCWebDeploymentTool"
/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
</Configuration>
<Configuration
Name="Release_PGOInstrument|Win32"
@@ -249,6 +257,9 @@ <Tool
Name="VCWebDeploymentTool"
/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
</Configuration>
<Configuration
Name="Release_PGOOptimize|Win32"
@@ -309,6 +320,9 @@ <Tool
Name="VCWebDeploymentTool"
/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
</Configuration>
<Configuration
Name="Debug_CFLite|Win32"
@@ -367,6 +381,9 @@ <Tool
Name="VCWebDeploymentTool"
/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
</Configuration>
<Configuration
Name="Release_CFLite|Win32"
@@ -426,6 +443,9 @@ <Tool
Name="VCWebDeploymentTool"
/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
</Configuration>
<Configuration
Name="Debug_All|Win32"
@@ -484,6 +504,71 @@ <Tool
Name="VCWebDeploymentTool"
/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_LTCG|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\FeatureDefines.vsprops;$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\release.vsprops;.\JavaScriptCoreCommon.vsprops;.\JavaScriptCoreCF.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
</Configuration>
</Configurations>
<References>
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj index c0ecd45..7c26a9c 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj @@ -73,7 +73,6 @@ ConfigurationType="4"
InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\FeatureDefines.vsprops;$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\release.vsprops;.\WTFCommon.vsprops"
CharacterSet="1"
- WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -228,6 +227,60 @@ Name="VCPostBuildEventTool"
/>
</Configuration>
+ <Configuration
+ Name="Release_LTCG|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\FeatureDefines.vsprops;$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\release.vsprops;.\WTFCommon.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ ProgramDataBaseFileName="$(OutDir)\$(TargetName).vc80.pdb"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
</Configurations>
<References>
</References>
@@ -447,6 +500,14 @@ DisableSpecificWarnings="4702"
/>
</FileConfiguration>
+ <FileConfiguration
+ Name="Release_LTCG|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableSpecificWarnings="4702"
+ />
+ </FileConfiguration>
</File>
<File
RelativePath="..\..\wtf\FastMalloc.h"
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/jsc/jsc.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/jsc/jsc.vcproj index 029a4b0..47861ae 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/jsc/jsc.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/jsc/jsc.vcproj @@ -81,7 +81,6 @@ ConfigurationType="1"
InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\release.vsprops;.\jscCommon.vsprops"
CharacterSet="1"
- WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -321,6 +320,68 @@ Name="VCPostBuildEventTool"
/>
</Configuration>
+ <Configuration
+ Name="Release_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\release.vsprops;.\jscCommon.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
</Configurations>
<References>
</References>
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapi.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapi.vcproj index 9581e54..c786abd 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapi.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapi.vcproj @@ -81,7 +81,6 @@ ConfigurationType="1"
InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\release.vsprops;.\testapiCommon.vsprops;..\JavaScriptCore\JavaScriptCoreCF.vsprops"
CharacterSet="1"
- WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -383,6 +382,68 @@ Name="VCPostBuildEventTool"
/>
</Configuration>
+ <Configuration
+ Name="Release_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\release.vsprops;.\testapiCommon.vsprops;..\JavaScriptCore\JavaScriptCoreCF.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
</Configurations>
<References>
</References>
@@ -438,6 +499,14 @@ CompileAs="2"
/>
</FileConfiguration>
+ <FileConfiguration
+ Name="Release_LTCG|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ CompileAs="2"
+ />
+ </FileConfiguration>
</File>
<File
RelativePath="..\..\API\tests\testapi.js"
diff --git a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index d134a73..a1e1c5c 100644 --- a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -555,6 +555,7 @@ E1EE793D0D6C9B9200FEA3BA /* ThreadingPthreads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1EE793C0D6C9B9200FEA3BA /* ThreadingPthreads.cpp */; }; E1EF79AA0CE97BA60088D500 /* UTF8.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1EF79A80CE97BA60088D500 /* UTF8.cpp */; }; E48E0F2D0F82151700A8CA37 /* FastAllocBase.h in Headers */ = {isa = PBXBuildFile; fileRef = E48E0F2C0F82151700A8CA37 /* FastAllocBase.h */; settings = {ATTRIBUTES = (Private, ); }; }; + F3BD31ED126735770065467F /* TextPosition.h in Headers */ = {isa = PBXBuildFile; fileRef = F3BD31D0126730180065467F /* TextPosition.h */; settings = {ATTRIBUTES = (Private, ); }; }; FE1B447A0ECCD73B004F4DD1 /* StdLibExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = FE1B44790ECCD73B004F4DD1 /* StdLibExtras.h */; settings = {ATTRIBUTES = (Private, ); }; }; /* End PBXBuildFile section */ @@ -1144,6 +1145,7 @@ E1EF79A80CE97BA60088D500 /* UTF8.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UTF8.cpp; sourceTree = "<group>"; }; E1EF79A90CE97BA60088D500 /* UTF8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UTF8.h; sourceTree = "<group>"; }; E48E0F2C0F82151700A8CA37 /* FastAllocBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FastAllocBase.h; sourceTree = "<group>"; }; + F3BD31D0126730180065467F /* TextPosition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextPosition.h; path = text/TextPosition.h; sourceTree = "<group>"; }; F5BB2BC5030F772101FCFE1D /* Completion.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = Completion.h; sourceTree = "<group>"; tabWidth = 8; }; F5C290E60284F98E018635CA /* JavaScriptCorePrefix.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptCorePrefix.h; sourceTree = "<group>"; tabWidth = 8; }; F68EBB8C0255D4C601FF60F7 /* config.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; tabWidth = 8; }; @@ -1860,6 +1862,7 @@ 868BFA07117CEFD100B908B1 /* StringImpl.h */, 86B99AE2117E578100DF5A90 /* StringImplBase.h */, 8626BECE11928E3900782FAB /* StringStatics.cpp */, + F3BD31D0126730180065467F /* TextPosition.h */, 868BFA15117CF19900B908B1 /* WTFString.cpp */, 868BFA16117CF19900B908B1 /* WTFString.h */, ); @@ -2349,6 +2352,7 @@ 90213E3E123A40C200D422F3 /* MemoryStatistics.h in Headers */, A730B6121250068F009D25B1 /* StrictEvalActivation.h in Headers */, 933F5CDC1269229B0049191E /* NullPtr.h in Headers */, + F3BD31ED126735770065467F /* TextPosition.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2442,7 +2446,6 @@ isa = PBXProject; buildConfigurationList = 149C277108902AFE008A9EFC /* Build configuration list for PBXProject "JavaScriptCore" */; compatibilityVersion = "Xcode 2.4"; - developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, diff --git a/JavaScriptCore/JavaScriptCorePrefix.h b/JavaScriptCore/JavaScriptCorePrefix.h index 13b21bb..21d6204 100644 --- a/JavaScriptCore/JavaScriptCorePrefix.h +++ b/JavaScriptCore/JavaScriptCorePrefix.h @@ -33,3 +33,4 @@ /* Work around bug with C++ library that screws up Objective-C++ when exception support is disabled. */ #undef try #undef catch + diff --git a/JavaScriptCore/assembler/AbstractMacroAssembler.h b/JavaScriptCore/assembler/AbstractMacroAssembler.h index 5db2cb9..1fa5ec7 100644 --- a/JavaScriptCore/assembler/AbstractMacroAssembler.h +++ b/JavaScriptCore/assembler/AbstractMacroAssembler.h @@ -26,8 +26,8 @@ #ifndef AbstractMacroAssembler_h #define AbstractMacroAssembler_h -#include <MacroAssemblerCodeRef.h> -#include <CodeLocation.h> +#include "CodeLocation.h" +#include "MacroAssemblerCodeRef.h" #include <wtf/Noncopyable.h> #include <wtf/UnusedParam.h> diff --git a/JavaScriptCore/assembler/CodeLocation.h b/JavaScriptCore/assembler/CodeLocation.h index cab28cd..e29029b 100644 --- a/JavaScriptCore/assembler/CodeLocation.h +++ b/JavaScriptCore/assembler/CodeLocation.h @@ -26,8 +26,7 @@ #ifndef CodeLocation_h #define CodeLocation_h - -#include <MacroAssemblerCodeRef.h> +#include "MacroAssemblerCodeRef.h" #if ENABLE(ASSEMBLER) diff --git a/JavaScriptCore/bytecode/CodeBlock.cpp b/JavaScriptCore/bytecode/CodeBlock.cpp index 55101d4..bcd2af3 100644 --- a/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/JavaScriptCore/bytecode/CodeBlock.cpp @@ -663,6 +663,11 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& printUnaryOp(exec, location, it, "bitnot"); break; } + case op_check_has_instance: { + int base = (++it)->u.operand; + printf("[%4d] check_has_instance\t\t %s\n", location, registerName(exec, base).data()); + break; + } case op_instanceof: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; @@ -1187,11 +1192,14 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& printf("[%4d] throw\t\t %s\n", location, registerName(exec, r0).data()); break; } - case op_new_error: { - int r0 = (++it)->u.operand; - int errorType = (++it)->u.operand; + case op_throw_reference_error: { int k0 = (++it)->u.operand; - printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(exec, r0).data(), errorType, constantName(exec, k0, getConstant(k0)).data()); + printf("[%4d] throw_reference_error\t %s\n", location, constantName(exec, k0, getConstant(k0)).data()); + break; + } + case op_throw_syntax_error: { + int k0 = (++it)->u.operand; + printf("[%4d] throw_syntax_error\t %s\n", location, constantName(exec, k0, getConstant(k0)).data()); break; } case op_jsr: { @@ -1617,7 +1625,7 @@ int CodeBlock::lineNumberForBytecodeOffset(CallFrame* callFrame, unsigned byteco return m_exceptionInfo->m_lineInfo[low - 1].lineNumber; } -int CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset) +void CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset) { ASSERT(bytecodeOffset < m_instructionCount); @@ -1627,7 +1635,7 @@ int CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned b startOffset = 0; endOffset = 0; divot = 0; - return lineNumberForBytecodeOffset(callFrame, bytecodeOffset); + return; } int low = 0; @@ -1639,43 +1647,19 @@ int CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned b else high = mid; } - + ASSERT(low); if (!low) { startOffset = 0; endOffset = 0; divot = 0; - return lineNumberForBytecodeOffset(callFrame, bytecodeOffset); + return; } startOffset = m_exceptionInfo->m_expressionInfo[low - 1].startOffset; endOffset = m_exceptionInfo->m_expressionInfo[low - 1].endOffset; divot = m_exceptionInfo->m_expressionInfo[low - 1].divotPoint + m_sourceOffset; - return lineNumberForBytecodeOffset(callFrame, bytecodeOffset); -} - -bool CodeBlock::getByIdExceptionInfoForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, OpcodeID& opcodeID) -{ - ASSERT(bytecodeOffset < m_instructionCount); - - if (!reparseForExceptionInfoIfNecessary(callFrame) || !m_exceptionInfo->m_getByIdExceptionInfo.size()) - return false; - - int low = 0; - int high = m_exceptionInfo->m_getByIdExceptionInfo.size(); - while (low < high) { - int mid = low + (high - low) / 2; - if (m_exceptionInfo->m_getByIdExceptionInfo[mid].bytecodeOffset <= bytecodeOffset) - low = mid + 1; - else - high = mid; - } - - if (!low || m_exceptionInfo->m_getByIdExceptionInfo[low - 1].bytecodeOffset != bytecodeOffset) - return false; - - opcodeID = m_exceptionInfo->m_getByIdExceptionInfo[low - 1].isOpCreateThis ? op_create_this : op_instanceof; - return true; + return; } #if ENABLE(JIT) @@ -1770,7 +1754,6 @@ void CodeBlock::shrinkToFit() if (m_exceptionInfo) { m_exceptionInfo->m_expressionInfo.shrinkToFit(); m_exceptionInfo->m_lineInfo.shrinkToFit(); - m_exceptionInfo->m_getByIdExceptionInfo.shrinkToFit(); } if (m_rareData) { diff --git a/JavaScriptCore/bytecode/CodeBlock.h b/JavaScriptCore/bytecode/CodeBlock.h index 68acae4..54acd50 100644 --- a/JavaScriptCore/bytecode/CodeBlock.h +++ b/JavaScriptCore/bytecode/CodeBlock.h @@ -93,14 +93,6 @@ namespace JSC { int32_t lineNumber; }; - // Both op_construct and op_instanceof require a use of op_get_by_id to get - // the prototype property from an object. The exception messages for exceptions - // thrown by these instances op_get_by_id need to reflect this. - struct GetByIdExceptionInfo { - unsigned bytecodeOffset : 31; - bool isOpCreateThis : 1; - }; - #if ENABLE(JIT) struct CallLinkInfo { CallLinkInfo() @@ -265,7 +257,6 @@ namespace JSC { struct ExceptionInfo : FastAllocBase { Vector<ExpressionRangeInfo> m_expressionInfo; Vector<LineInfo> m_lineInfo; - Vector<GetByIdExceptionInfo> m_getByIdExceptionInfo; #if ENABLE(JIT) Vector<CallReturnOffsetToBytecodeOffset> m_callReturnIndexVector; @@ -317,8 +308,7 @@ namespace JSC { HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset); int lineNumberForBytecodeOffset(CallFrame*, unsigned bytecodeOffset); - int expressionRangeForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset); - bool getByIdExceptionInfoForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, OpcodeID&); + void expressionRangeForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset); #if ENABLE(JIT) void addCaller(CallLinkInfo* caller) @@ -468,7 +458,6 @@ namespace JSC { PassOwnPtr<ExceptionInfo> extractExceptionInfo(); void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_expressionInfo.append(expressionInfo); } - void addGetByIdExceptionInfo(const GetByIdExceptionInfo& info) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_getByIdExceptionInfo.append(info); } size_t numberOfLineInfos() const { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.size(); } void addLineInfo(const LineInfo& lineInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_lineInfo.append(lineInfo); } diff --git a/JavaScriptCore/bytecode/Opcode.h b/JavaScriptCore/bytecode/Opcode.h index 8ee82e7..6c1c6b2 100644 --- a/JavaScriptCore/bytecode/Opcode.h +++ b/JavaScriptCore/bytecode/Opcode.h @@ -82,6 +82,7 @@ namespace JSC { macro(op_bitor, 5) \ macro(op_bitnot, 3) \ \ + macro(op_check_has_instance, 2) \ macro(op_instanceof, 5) \ macro(op_typeof, 3) \ macro(op_is_undefined, 3) \ @@ -183,7 +184,8 @@ namespace JSC { \ macro(op_catch, 2) \ macro(op_throw, 2) \ - macro(op_new_error, 4) \ + macro(op_throw_reference_error, 2) \ + macro(op_throw_syntax_error, 2) \ \ macro(op_jsr, 3) \ macro(op_sret, 2) \ diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index 7538314..1fa5aa4 100644 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -443,7 +443,6 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug emitOpcode(op_get_callee); instructions().append(func->index()); // Load prototype. - emitGetByIdExceptionInfo(op_create_this); emitGetById(funcProto.get(), func.get(), globalData()->propertyNames->prototype); emitOpcode(op_create_this); @@ -1158,6 +1157,12 @@ bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& inde return true; } +void BytecodeGenerator::emitCheckHasInstance(RegisterID* base) +{ + emitOpcode(op_check_has_instance); + instructions().append(base->index()); +} + RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype) { emitOpcode(op_instanceof); @@ -2050,13 +2055,16 @@ RegisterID* BytecodeGenerator::emitCatch(RegisterID* targetRegister, Label* star return targetRegister; } -RegisterID* BytecodeGenerator::emitNewError(RegisterID* dst, bool isReferenceError, JSValue message) +void BytecodeGenerator::emitThrowReferenceError(const UString& message) { - emitOpcode(op_new_error); - instructions().append(dst->index()); - instructions().append(isReferenceError); - instructions().append(addConstantValue(message)->index()); - return dst; + emitOpcode(op_throw_reference_error); + instructions().append(addConstantValue(jsString(globalData(), message))->index()); +} + +void BytecodeGenerator::emitThrowSyntaxError(const UString& message) +{ + emitOpcode(op_throw_syntax_error); + instructions().append(addConstantValue(jsString(globalData(), message))->index()); } PassRefPtr<Label> BytecodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, Label* finally) @@ -2211,9 +2219,8 @@ RegisterID* BytecodeGenerator::emitThrowExpressionTooDeepException() // that from an arbitrary node. However, calling emitExpressionInfo without any useful data // is still good enough to get us an accurate line number. emitExpressionInfo(0, 0, 0); - RegisterID* exception = emitNewError(newTemporary(), false, jsString(globalData(), "Expression too deep")); - emitThrow(exception); - return exception; + emitThrowSyntaxError("Expression too deep"); + return newTemporary(); } void BytecodeGenerator::setIsNumericCompareFunction(bool isNumericCompareFunction) diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/JavaScriptCore/bytecompiler/BytecodeGenerator.h index b189565..499d232 100644 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -230,8 +230,10 @@ namespace JSC { LineInfo info = { instructions().size(), n->lineNo() }; m_codeBlock->addLineInfo(info); } - if (m_emitNodeDepth >= s_maxEmitNodeDepth) + if (m_emitNodeDepth >= s_maxEmitNodeDepth) { emitThrowExpressionTooDeepException(); + return; + } ++m_emitNodeDepth; n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue); --m_emitNodeDepth; @@ -266,17 +268,6 @@ namespace JSC { m_codeBlock->addExpressionInfo(info); } - void emitGetByIdExceptionInfo(OpcodeID opcodeID) - { - // Only op_construct and op_instanceof need exception info for - // a preceding op_get_by_id. - ASSERT(opcodeID == op_create_this || opcodeID == op_instanceof); - GetByIdExceptionInfo info; - info.bytecodeOffset = instructions().size(); - info.isOpCreateThis = (opcodeID == op_create_this); - m_codeBlock->addGetByIdExceptionInfo(info); - } - ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) { return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure; @@ -320,6 +311,7 @@ namespace JSC { RegisterID* emitPostInc(RegisterID* dst, RegisterID* srcDst); RegisterID* emitPostDec(RegisterID* dst, RegisterID* srcDst); + void emitCheckHasInstance(RegisterID* base); RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype); RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); } RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); } @@ -380,7 +372,9 @@ namespace JSC { emitUnaryNoDstOp(op_throw, exc); } - RegisterID* emitNewError(RegisterID* dst, bool isReferenceError, JSValue message); + void emitThrowReferenceError(const UString& message); + void emitThrowSyntaxError(const UString& message); + void emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value); RegisterID* emitPushScope(RegisterID* scope); diff --git a/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/JavaScriptCore/bytecompiler/NodesCodegen.cpp index 47129d5..a850c96 100644 --- a/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -76,34 +76,18 @@ namespace JSC { // ------------------------------ ThrowableExpressionData -------------------------------- -static void substitute(UString& string, const UString& substring) -{ - size_t position = string.find("%s"); - ASSERT(position != notFound); - string = makeUString(string.substringSharingImpl(0, position), substring, string.substringSharingImpl(position + 2)); -} - -RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, bool isReferenceError, const char* message) +RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const UString& message) { generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RegisterID* exception = generator.emitNewError(generator.newTemporary(), isReferenceError, jsString(generator.globalData(), message)); - generator.emitThrow(exception); - return exception; + generator.emitThrowReferenceError(message); + return generator.newTemporary(); } -RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, bool isReferenceError, const char* messageTemplate, const UString& label) +RegisterID* ThrowableExpressionData::emitThrowSyntaxError(BytecodeGenerator& generator, const UString& message) { - UString message = messageTemplate; - substitute(message, label); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RegisterID* exception = generator.emitNewError(generator.newTemporary(), isReferenceError, jsString(generator.globalData(), message)); - generator.emitThrow(exception); - return exception; -} - -inline RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, bool isReferenceError, const char* messageTemplate, const Identifier& label) -{ - return emitThrowError(generator, isReferenceError, messageTemplate, label.ustring()); + generator.emitThrowSyntaxError(message); + return generator.newTemporary(); } // ------------------------------ NullNode ------------------------------------- @@ -148,7 +132,7 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d { RefPtr<RegExp> regExp = generator.globalData()->regExpCache()->lookupOrCreate(m_pattern.ustring(), m_flags.ustring()); if (!regExp->isValid()) - return emitThrowError(generator, false, "Invalid regular expression: %s", regExp->errorMessage()); + return emitThrowSyntaxError(generator, makeUString("Invalid regular expression: ", regExp->errorMessage())); if (dst == generator.ignoredResult()) return 0; return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get()); @@ -661,7 +645,7 @@ RegisterID* PostfixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterI RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - return emitThrowError(generator, true, m_operator == OpPlusPlus + return emitThrowReferenceError(generator, m_operator == OpPlusPlus ? "Postfix ++ operator applied to value that is not a reference." : "Postfix -- operator applied to value that is not a reference."); } @@ -826,7 +810,7 @@ RegisterID* PrefixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - return emitThrowError(generator, true, m_operator == OpPlusPlus + return emitThrowReferenceError(generator, m_operator == OpPlusPlus ? "Prefix ++ operator applied to value that is not a reference." : "Prefix -- operator applied to value that is not a reference."); } @@ -1032,7 +1016,9 @@ RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterI RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitGetByIdExceptionInfo(op_instanceof); + generator.emitCheckHasInstance(src2.get()); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); @@ -1269,7 +1255,7 @@ RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, Regist RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - return emitThrowError(generator, true, "Left side of assignment is not a reference."); + return emitThrowReferenceError(generator, "Left side of assignment is not a reference."); } // ------------------------------ AssignBracketNode ----------------------------------- @@ -1579,7 +1565,7 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); if (!m_lexpr->isLocation()) - return emitThrowError(generator, true, "Left side of for-in statement is not a reference."); + return emitThrowReferenceError(generator, "Left side of for-in statement is not a reference."); generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); @@ -1656,10 +1642,11 @@ RegisterID* ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* LabelScope* scope = generator.continueTarget(m_ident); - if (!scope) - return m_ident.isEmpty() - ? emitThrowError(generator, false, "Invalid continue statement.") - : emitThrowError(generator, false, "Undefined label: '%s'.", m_ident); + if (!scope) { + if (m_ident.isEmpty()) + return emitThrowSyntaxError(generator, "Invalid continue statement."); + return emitThrowSyntaxError(generator, makeUString("Undefined label: '", m_ident.ustring(), "'.")); + } generator.emitJumpScopes(scope->continueTarget(), scope->scopeDepth()); return dst; @@ -1674,10 +1661,11 @@ RegisterID* BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds LabelScope* scope = generator.breakTarget(m_ident); - if (!scope) - return m_ident.isEmpty() - ? emitThrowError(generator, false, "Invalid break statement.") - : emitThrowError(generator, false, "Undefined label: '%s'.", m_ident); + if (!scope) { + if (m_ident.isEmpty()) + return emitThrowSyntaxError(generator, "Invalid break statement."); + return emitThrowSyntaxError(generator, makeUString("Undefined label: '", m_ident.ustring(), "'.")); + } generator.emitJumpScopes(scope->breakTarget(), scope->scopeDepth()); return dst; @@ -1689,7 +1677,7 @@ RegisterID* ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d { generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); if (generator.codeType() != FunctionCode) - return emitThrowError(generator, false, "Invalid return statement."); + return emitThrowSyntaxError(generator, "Invalid return statement."); if (dst == generator.ignoredResult()) dst = 0; @@ -1895,7 +1883,7 @@ RegisterID* LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); if (generator.breakTarget(m_name)) - return emitThrowError(generator, false, "Duplicate label: %s.", m_name); + return emitThrowSyntaxError(generator, makeUString("Duplicate label: ", m_name.ustring(), ".")); RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); RegisterID* r0 = generator.emitNode(dst, m_statement); diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp index 68be9fa..0a1be48 100644 --- a/JavaScriptCore/interpreter/Interpreter.cpp +++ b/JavaScriptCore/interpreter/Interpreter.cpp @@ -38,6 +38,7 @@ #include "Collector.h" #include "Debugger.h" #include "DebuggerCallFrame.h" +#include "ErrorInstance.h" #include "EvalCodeCache.h" #include "ExceptionHelpers.h" #include "GetterSetter.h" @@ -60,6 +61,7 @@ #include "Register.h" #include "SamplingTool.h" #include "StrictEvalActivation.h" +#include "UStringConcatenate.h" #include <limits.h> #include <stdio.h> #include <wtf/Threading.h> @@ -112,7 +114,7 @@ NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, J return true; } } while (++iter != end); - exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionValue = createUndefinedVariableError(callFrame, ident); return false; } @@ -152,7 +154,7 @@ NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vP return true; } } while (++iter != end); - exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionValue = createUndefinedVariableError(callFrame, ident); return false; } @@ -192,7 +194,7 @@ NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* return true; } - exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionValue = createUndefinedVariableError(callFrame, ident); return false; } @@ -237,7 +239,7 @@ NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instru o = *iter; ++iter; } while (true); - exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionValue = createUndefinedVariableError(callFrame, ident); return false; } ++iter; @@ -272,7 +274,7 @@ NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instru return true; } - exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionValue = createUndefinedVariableError(callFrame, ident); return false; } @@ -322,7 +324,7 @@ NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Inst ++iter; } while (iter != end); - exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionValue = createUndefinedVariableError(callFrame, ident); return false; } @@ -366,19 +368,19 @@ ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newC } #if ENABLE(INTERPRETER) -static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData) +static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, JSValue value, JSValue& exceptionData) { if (value.isObject()) return false; - exceptionData = createInvalidParamError(callFrame, "in" , value, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionData = createInvalidParamError(callFrame, "in" , value); return true; } -static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData) +static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, JSValue value, JSValue& exceptionData) { if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance()) return false; - exceptionData = createInvalidParamError(callFrame, "instanceof" , value, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionData = createInvalidParamError(callFrame, "instanceof" , value); return true; } #endif @@ -605,6 +607,54 @@ NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue ex return true; } +static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset) +{ + exception->clearAppendSourceToMessage(); + + int startOffset = 0; + int endOffset = 0; + int divotPoint = 0; + + CodeBlock* codeBlock = callFrame->codeBlock(); + codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divotPoint, startOffset, endOffset); + + int expressionStart = divotPoint - startOffset; + int expressionStop = divotPoint + endOffset; + + if (!expressionStop || expressionStart > codeBlock->source()->length()) + return; + + JSGlobalData* globalData = &callFrame->globalData(); + JSValue jsMessage = exception->getDirect(globalData->propertyNames->message); + if (!jsMessage || !jsMessage.isString()) + return; + + UString message = asString(jsMessage)->value(callFrame); + + if (expressionStart < expressionStop) + message = makeUString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')"); + else { + // No range information, so give a few characters of context + const UChar* data = codeBlock->source()->data(); + int dataLength = codeBlock->source()->length(); + int start = expressionStart; + int stop = expressionStart; + // Get up to 20 characters of context to the left and right of the divot, clamping to the line. + // then strip whitespace. + while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n') + start--; + while (start < (expressionStart - 1) && isStrWhiteSpace(data[start])) + start++; + while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n') + stop++; + while (stop > expressionStart && isStrWhiteSpace(data[stop])) + stop--; + message = makeUString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')"); + } + + exception->putDirect(globalData->propertyNames->message, jsString(globalData, message)); +} + NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset, bool explicitThrow) { // Set up the exception object @@ -612,28 +662,20 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV CodeBlock* codeBlock = callFrame->codeBlock(); if (exceptionValue.isObject()) { JSObject* exception = asObject(exceptionValue); - if (exception->isNotAnObjectErrorStub()) { - exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), bytecodeOffset, codeBlock); - exceptionValue = exception; - } else { - if (!hasErrorInfo(callFrame, exception)) { - if (explicitThrow) { - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divotPoint, startOffset, endOffset); - addErrorInfo(callFrame, exception, line, codeBlock->ownerExecutable()->source(), divotPoint, startOffset, endOffset, false); - } else - addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset), codeBlock->ownerExecutable()->source()); - } - - ComplType exceptionType = exception->exceptionType(); - if (exceptionType == Interrupted || exceptionType == Terminated) { - while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) { - // Don't need handler checks or anything, we just want to unroll all the JS callframes possible. - } - return 0; + if (!explicitThrow && exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage()) + appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset); + + // FIXME: should only really be adding these properties to VM generated exceptions, + // but the inspector currently requires these for all thrown objects. + if (!hasErrorInfo(callFrame, exception)) + addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset), codeBlock->ownerExecutable()->source()); + + ComplType exceptionType = exception->exceptionType(); + if (exceptionType == Interrupted || exceptionType == Terminated) { + while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) { + // Don't need handler checks or anything, we just want to unroll all the JS callframes possible. } + return 0; } } @@ -2098,6 +2140,23 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi vPC += OPCODE_LENGTH(op_not); NEXT_INSTRUCTION(); } + DEFINE_OPCODE(op_check_has_instance) { + /* check_has_instance constructor(r) + + Check 'constructor' is an object with the internal property + [HasInstance] (i.e. is a function ... *shakes head sadly at + JSC API*). Raises an exception if register constructor is not + an valid parameter for instanceof. + */ + int base = vPC[1].u.operand; + JSValue baseVal = callFrame->r(base).jsValue(); + + if (isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue)) + goto vm_throw; + + vPC += OPCODE_LENGTH(op_check_has_instance); + NEXT_INSTRUCTION(); + } DEFINE_OPCODE(op_instanceof) { /* instanceof dst(r) value(r) constructor(r) constructorProto(r) @@ -2118,8 +2177,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi JSValue baseVal = callFrame->r(base).jsValue(); - if (isInvalidParamForInstanceOf(callFrame, codeBlock, vPC, baseVal, exceptionValue)) - goto vm_throw; + ASSERT(!isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue)); bool result = asObject(baseVal)->hasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue()); CHECK_FOR_EXCEPTION(); @@ -2240,7 +2298,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int base = vPC[3].u.operand; JSValue baseVal = callFrame->r(base).jsValue(); - if (isInvalidParamForIn(callFrame, codeBlock, vPC, baseVal, exceptionValue)) + if (isInvalidParamForIn(callFrame, baseVal, exceptionValue)) goto vm_throw; JSObject* baseObj = asObject(baseVal); @@ -3885,7 +3943,7 @@ skip_id_custom_self: ASSERT(callType == CallTypeNone); - exceptionValue = createNotAFunctionError(callFrame, v, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionValue = createNotAFunctionError(callFrame, v); goto vm_throw; } DEFINE_OPCODE(op_load_varargs) { @@ -3917,7 +3975,7 @@ skip_id_custom_self: argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - static_cast<int32_t>(argCount) - 1]; } else if (!arguments.isUndefinedOrNull()) { if (!arguments.isObject()) { - exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments); goto vm_throw; } if (asObject(arguments)->classInfo() == &Arguments::info) { @@ -3958,7 +4016,7 @@ skip_id_custom_self: CHECK_FOR_EXCEPTION(); } } else { - exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments); goto vm_throw; } } @@ -4043,7 +4101,7 @@ skip_id_custom_self: ASSERT(callType == CallTypeNone); - exceptionValue = createNotAFunctionError(callFrame, v, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionValue = createNotAFunctionError(callFrame, v); goto vm_throw; } DEFINE_OPCODE(op_tear_off_activation) { @@ -4387,7 +4445,7 @@ skip_id_custom_self: ASSERT(constructType == ConstructTypeNone); - exceptionValue = createNotAConstructorError(callFrame, v, vPC - codeBlock->instructions().begin(), codeBlock); + exceptionValue = createNotAConstructorError(callFrame, v); goto vm_throw; } DEFINE_OPCODE(op_strcat) { @@ -4584,24 +4642,27 @@ skip_id_custom_self: vPC = codeBlock->instructions().begin() + handler->target; NEXT_INSTRUCTION(); } - DEFINE_OPCODE(op_new_error) { - /* new_error dst(r) type(n) message(k) + DEFINE_OPCODE(op_throw_reference_error) { + /* op_throw_reference_error message(k) - Constructs a new Error instance using the original - constructor, using immediate number n as the type and - constant message as the message string. The result is - written to register dst. + Constructs a new reference Error instance using the + original constructor, using constant message as the + message string. The result is thrown. */ - int dst = vPC[1].u.operand; - int isReference = vPC[2].u.operand; - UString message = callFrame->r(vPC[3].u.operand).jsValue().toString(callFrame); - - JSObject* error = isReference ? createReferenceError(callFrame, message) : createSyntaxError(callFrame, message); - addErrorInfo(globalData, error, codeBlock->lineNumberForBytecodeOffset(callFrame, vPC - codeBlock->instructions().begin()), codeBlock->ownerExecutable()->source()); - callFrame->r(dst) = JSValue(error); + UString message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame); + exceptionValue = JSValue(createReferenceError(callFrame, message)); + goto vm_throw; + } + DEFINE_OPCODE(op_throw_syntax_error) { + /* op_throw_syntax_error message(k) - vPC += OPCODE_LENGTH(op_new_error); - NEXT_INSTRUCTION(); + Constructs a new syntax Error instance using the + original constructor, using constant message as the + message string. The result is thrown. + */ + UString message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame); + exceptionValue = JSValue(createSyntaxError(callFrame, message)); + goto vm_throw; } DEFINE_OPCODE(op_end) { /* end result(r) diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp index e5be43b..3f2ec59 100644 --- a/JavaScriptCore/jit/JIT.cpp +++ b/JavaScriptCore/jit/JIT.cpp @@ -241,6 +241,7 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_get_global_var) DEFINE_OP(op_get_pnames) DEFINE_OP(op_get_scoped_var) + DEFINE_OP(op_check_has_instance) DEFINE_OP(op_instanceof) DEFINE_OP(op_jeq_null) DEFINE_OP(op_jfalse) @@ -271,7 +272,6 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_neq) DEFINE_OP(op_neq_null) DEFINE_OP(op_new_array) - DEFINE_OP(op_new_error) DEFINE_OP(op_new_func) DEFINE_OP(op_new_func_exp) DEFINE_OP(op_new_object) @@ -317,6 +317,8 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_tear_off_activation) DEFINE_OP(op_tear_off_arguments) DEFINE_OP(op_throw) + DEFINE_OP(op_throw_reference_error) + DEFINE_OP(op_throw_syntax_error) DEFINE_OP(op_to_jsnumber) DEFINE_OP(op_to_primitive) @@ -401,6 +403,7 @@ void JIT::privateCompileSlowCases() 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_check_has_instance) DEFINE_SLOWCASE_OP(op_instanceof) DEFINE_SLOWCASE_OP(op_jfalse) DEFINE_SLOWCASE_OP(op_jnless) diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h index 3ef0538..907a774 100644 --- a/JavaScriptCore/jit/JIT.h +++ b/JavaScriptCore/jit/JIT.h @@ -402,7 +402,7 @@ namespace JSC { static const int sequenceGetByIdHotPathInstructionSpace = 36; static const int sequenceGetByIdHotPathConstantSpace = 4; // sequenceGetByIdSlowCase - static const int sequenceGetByIdSlowCaseInstructionSpace = 40; + static const int sequenceGetByIdSlowCaseInstructionSpace = 56; static const int sequenceGetByIdSlowCaseConstantSpace = 2; // sequencePutById static const int sequencePutByIdInstructionSpace = 36; @@ -755,6 +755,7 @@ namespace JSC { void emit_op_get_global_var(Instruction*); void emit_op_get_scoped_var(Instruction*); void emit_op_init_lazy_reg(Instruction*); + void emit_op_check_has_instance(Instruction*); void emit_op_instanceof(Instruction*); void emit_op_jeq_null(Instruction*); void emit_op_jfalse(Instruction*); @@ -783,7 +784,6 @@ namespace JSC { void emit_op_neq(Instruction*); void emit_op_neq_null(Instruction*); void emit_op_new_array(Instruction*); - void emit_op_new_error(Instruction*); void emit_op_new_func(Instruction*); void emit_op_new_func_exp(Instruction*); void emit_op_new_object(Instruction*); @@ -828,6 +828,8 @@ namespace JSC { void emit_op_tear_off_activation(Instruction*); void emit_op_tear_off_arguments(Instruction*); void emit_op_throw(Instruction*); + void emit_op_throw_reference_error(Instruction*); + void emit_op_throw_syntax_error(Instruction*); void emit_op_to_jsnumber(Instruction*); void emit_op_to_primitive(Instruction*); void emit_op_unexpected_load(Instruction*); @@ -854,6 +856,7 @@ namespace JSC { 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_check_has_instance(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_instanceof(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_jfalse(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_jnless(Instruction*, Vector<SlowCaseEntry>::iterator&); diff --git a/JavaScriptCore/jit/JITInlineMethods.h b/JavaScriptCore/jit/JITInlineMethods.h index 7611151..39ca4a5 100644 --- a/JavaScriptCore/jit/JITInlineMethods.h +++ b/JavaScriptCore/jit/JITInlineMethods.h @@ -122,8 +122,15 @@ ALWAYS_INLINE void JIT::beginUninterruptedSequence(int insnSpace, int constSpace ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace) { #if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL - ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) == insnSpace); - ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin == constSpace); + /* There are several cases when the uninterrupted sequence is larger than + * maximum required offset for pathing the same sequence. Eg.: if in a + * uninterrupted sequence the last macroassembler's instruction is a stub + * call, it emits store instruction(s) which should not be included in the + * calculation of length of uninterrupted sequence. So, the insnSpace and + * constSpace should be upper limit instead of hard limit. + */ + ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) <= insnSpace); + ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin <= constSpace); #endif JSInterfaceJIT::endUninterruptedSequence(); } diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp index 74170c1..d783581 100644 --- a/JavaScriptCore/jit/JITOpcodes.cpp +++ b/JavaScriptCore/jit/JITOpcodes.cpp @@ -378,6 +378,20 @@ void JIT::emit_op_new_object(Instruction* currentInstruction) JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand); } +void JIT::emit_op_check_has_instance(Instruction* currentInstruction) +{ + unsigned baseVal = currentInstruction[1].u.operand; + + emitGetVirtualRegister(baseVal, regT0); + + // Check that baseVal is a cell. + emitJumpSlowCaseIfNotJSCell(regT0, baseVal); + + // Check that baseVal 'ImplementsHasInstance'. + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); + addSlowCase(branchTest8(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsHasInstance))); +} + void JIT::emit_op_instanceof(Instruction* currentInstruction) { unsigned dst = currentInstruction[1].u.operand; @@ -391,15 +405,15 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) emitGetVirtualRegister(baseVal, regT0); emitGetVirtualRegister(proto, regT1); - // Check that baseVal & proto are cells. + // Check that proto are cells. baseVal must be a cell - this is checked by op_check_has_instance. emitJumpSlowCaseIfNotJSCell(regT2, value); - 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))); + // Fixme: this check is only needed because the JSC API allows HasInstance to be overridden; we should deprecate this. // 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))); @@ -1133,13 +1147,18 @@ void JIT::emit_op_switch_string(Instruction* currentInstruction) jump(regT0); } -void JIT::emit_op_new_error(Instruction* currentInstruction) +void JIT::emit_op_throw_reference_error(Instruction* currentInstruction) { - JITStubCall stubCall(this, cti_op_new_error); - stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); - stubCall.addArgument(ImmPtr(JSValue::encode(m_codeBlock->getConstant(currentInstruction[3].u.operand)))); - stubCall.addArgument(Imm32(m_bytecodeOffset)); - stubCall.call(currentInstruction[1].u.operand); + JITStubCall stubCall(this, cti_op_throw_reference_error); + stubCall.addArgument(ImmPtr(JSValue::encode(m_codeBlock->getConstant(currentInstruction[1].u.operand)))); + stubCall.call(); +} + +void JIT::emit_op_throw_syntax_error(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_throw_syntax_error); + stubCall.addArgument(ImmPtr(JSValue::encode(m_codeBlock->getConstant(currentInstruction[1].u.operand)))); + stubCall.call(); } void JIT::emit_op_debug(Instruction* currentInstruction) @@ -1475,6 +1494,17 @@ void JIT::emitSlow_op_nstricteq(Instruction* currentInstruction, Vector<SlowCase stubCall.call(currentInstruction[1].u.operand); } +void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned baseVal = currentInstruction[1].u.operand; + + linkSlowCaseIfNotJSCell(iter, baseVal); + linkSlowCase(iter); + JITStubCall stubCall(this, cti_op_check_has_instance); + stubCall.addArgument(baseVal, regT2); + stubCall.call(); +} + void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { unsigned dst = currentInstruction[1].u.operand; @@ -1483,7 +1513,6 @@ void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCas unsigned proto = currentInstruction[4].u.operand; linkSlowCaseIfNotJSCell(iter, value); - linkSlowCaseIfNotJSCell(iter, baseVal); linkSlowCaseIfNotJSCell(iter, proto); linkSlowCase(iter); linkSlowCase(iter); diff --git a/JavaScriptCore/jit/JITOpcodes32_64.cpp b/JavaScriptCore/jit/JITOpcodes32_64.cpp index 8e0226d..076649d 100644 --- a/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -512,6 +512,20 @@ void JIT::emit_op_new_object(Instruction* currentInstruction) JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand); } +void JIT::emit_op_check_has_instance(Instruction* currentInstruction) +{ + unsigned baseVal = currentInstruction[1].u.operand; + + emitLoadPayload(baseVal, regT0); + + // Check that baseVal is a cell. + emitJumpSlowCaseIfNotJSCell(baseVal); + + // Check that baseVal 'ImplementsHasInstance'. + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); + addSlowCase(branchTest8(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsHasInstance))); +} + void JIT::emit_op_instanceof(Instruction* currentInstruction) { unsigned dst = currentInstruction[1].u.operand; @@ -525,15 +539,15 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) emitLoadPayload(baseVal, regT0); emitLoadPayload(proto, regT1); - // Check that value, baseVal, and proto are cells. + // Check that proto are cells. baseVal must be a cell - this is checked by op_check_has_instance. 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))); - + + // Fixme: this check is only needed because the JSC API allows HasInstance to be overridden; we should deprecate this. // 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))); @@ -559,6 +573,18 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) emitStoreBool(dst, regT0); } +void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned baseVal = currentInstruction[1].u.operand; + + linkSlowCaseIfNotJSCell(iter, baseVal); + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_check_has_instance); + stubCall.addArgument(baseVal); + stubCall.call(); +} + void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { unsigned dst = currentInstruction[1].u.operand; @@ -567,7 +593,6 @@ void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCas unsigned proto = currentInstruction[4].u.operand; linkSlowCaseIfNotJSCell(iter, value); - linkSlowCaseIfNotJSCell(iter, baseVal); linkSlowCaseIfNotJSCell(iter, proto); linkSlowCase(iter); linkSlowCase(iter); @@ -1462,17 +1487,22 @@ void JIT::emit_op_switch_string(Instruction* currentInstruction) jump(regT0); } -void JIT::emit_op_new_error(Instruction* currentInstruction) +void JIT::emit_op_throw_reference_error(Instruction* currentInstruction) { - unsigned dst = currentInstruction[1].u.operand; - unsigned type = currentInstruction[2].u.operand; - unsigned message = currentInstruction[3].u.operand; + unsigned message = currentInstruction[1].u.operand; - JITStubCall stubCall(this, cti_op_new_error); - stubCall.addArgument(Imm32(type)); + JITStubCall stubCall(this, cti_op_throw_reference_error); stubCall.addArgument(m_codeBlock->getConstant(message)); - stubCall.addArgument(Imm32(m_bytecodeOffset)); - stubCall.call(dst); + stubCall.call(); +} + +void JIT::emit_op_throw_syntax_error(Instruction* currentInstruction) +{ + unsigned message = currentInstruction[1].u.operand; + + JITStubCall stubCall(this, cti_op_throw_syntax_error); + stubCall.addArgument(m_codeBlock->getConstant(message)); + stubCall.call(); } void JIT::emit_op_debug(Instruction* currentInstruction) diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp index 896b93d..36d36a2 100644 --- a/JavaScriptCore/jit/JITStubs.cpp +++ b/JavaScriptCore/jit/JITStubs.cpp @@ -1841,6 +1841,23 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_string_fail) #endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) +DEFINE_STUB_FUNCTION(void, op_check_has_instance) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + CallFrame* callFrame = stackFrame.callFrame; + JSValue baseVal = stackFrame.args[0].jsValue(); + + // ECMA-262 15.3.5.3: + // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function). +#ifndef NDEBUG + TypeInfo typeInfo(UnspecifiedType); + ASSERT(!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()); +#endif + stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal); + VM_THROW_EXCEPTION_AT_END(); +} + DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1860,10 +1877,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof) // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function). TypeInfo typeInfo(UnspecifiedType); if (!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()) { - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal, vPCIndex, codeBlock); + stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "instanceof", baseVal); VM_THROW_EXCEPTION(); } ASSERT(typeInfo.type() != UnspecifiedType); @@ -2201,10 +2215,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction) ASSERT(callType == CallTypeNone); - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal, vPCIndex, codeBlock); + stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal); VM_THROW_EXCEPTION(); } @@ -2307,9 +2318,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve) } } while (++iter != end); - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock); + stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION(); } @@ -2348,10 +2357,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct) ASSERT(constructType == ConstructTypeNone); - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createNotAConstructorError(callFrame, constrVal, vPCIndex, codeBlock); + stackFrame.globalData->exception = createNotAConstructorError(stackFrame.callFrame, constrVal); VM_THROW_EXCEPTION(); } @@ -2621,9 +2627,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs) } else if (!arguments.isUndefinedOrNull()) { if (!arguments.isObject()) { - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock); + stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments); VM_THROW_EXCEPTION(); } if (asObject(arguments)->classInfo() == &Arguments::info) { @@ -2664,9 +2668,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs) CHECK_FOR_EXCEPTION(); } } else { - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock); + stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments); VM_THROW_EXCEPTION(); } } @@ -2757,8 +2759,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip) } } while (++iter != end); - unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock); + stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION(); } @@ -2790,8 +2791,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global) return JSValue::encode(result); } - unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock); + stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION(); } @@ -3091,9 +3091,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base) ++iter; } while (iter != end); - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock); + stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION_AT_END(); return JSValue::encode(JSValue()); } @@ -3396,10 +3394,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_in) JSValue baseVal = stackFrame.args[1].jsValue(); if (!baseVal.isObject()) { - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "in", baseVal, vPCIndex, codeBlock); + stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "in", baseVal); VM_THROW_EXCEPTION(); } @@ -3563,19 +3558,24 @@ DEFINE_STUB_FUNCTION(void, op_put_setter) baseObj->defineSetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue())); } -DEFINE_STUB_FUNCTION(JSObject*, op_new_error) +DEFINE_STUB_FUNCTION(void, op_throw_reference_error) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned isReference = stackFrame.args[0].int32(); - UString message = stackFrame.args[1].jsValue().toString(callFrame); - unsigned bytecodeOffset = stackFrame.args[2].int32(); + UString message = stackFrame.args[0].jsValue().toString(callFrame); + stackFrame.globalData->exception = createReferenceError(callFrame, message); + VM_THROW_EXCEPTION_AT_END(); +} - JSObject* error = isReference ? createReferenceError(callFrame, message) : createSyntaxError(callFrame, message); - unsigned lineNumber = codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset); - return addErrorInfo(stackFrame.globalData, error, lineNumber, codeBlock->ownerExecutable()->source()); +DEFINE_STUB_FUNCTION(void, op_throw_syntax_error) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + CallFrame* callFrame = stackFrame.callFrame; + UString message = stackFrame.args[0].jsValue().toString(callFrame); + stackFrame.globalData->exception = createSyntaxError(callFrame, message); + VM_THROW_EXCEPTION_AT_END(); } DEFINE_STUB_FUNCTION(void, op_debug) diff --git a/JavaScriptCore/jit/JITStubs.h b/JavaScriptCore/jit/JITStubs.h index c27ee52..937134b 100644 --- a/JavaScriptCore/jit/JITStubs.h +++ b/JavaScriptCore/jit/JITStubs.h @@ -354,7 +354,6 @@ extern "C" { EncodedJSValue JIT_STUB cti_op_urshift(STUB_ARGS_DECLARATION); EncodedJSValue JIT_STUB cti_to_object(STUB_ARGS_DECLARATION); JSObject* JIT_STUB cti_op_new_array(STUB_ARGS_DECLARATION); - JSObject* JIT_STUB cti_op_new_error(STUB_ARGS_DECLARATION); JSObject* JIT_STUB cti_op_new_func(STUB_ARGS_DECLARATION); JSObject* JIT_STUB cti_op_new_func_exp(STUB_ARGS_DECLARATION); JSObject* JIT_STUB cti_op_new_object(STUB_ARGS_DECLARATION); @@ -373,6 +372,7 @@ extern "C" { int JIT_STUB cti_op_loop_if_lesseq(STUB_ARGS_DECLARATION); int JIT_STUB cti_timeout_check(STUB_ARGS_DECLARATION); int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION); + void JIT_STUB cti_op_check_has_instance(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_debug(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_end(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_jmp_scopes(STUB_ARGS_DECLARATION); @@ -393,6 +393,8 @@ extern "C" { void JIT_STUB cti_op_ret_scopeChain(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_tear_off_activation(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_tear_off_arguments(STUB_ARGS_DECLARATION); + void JIT_STUB cti_op_throw_reference_error(STUB_ARGS_DECLARATION); + void JIT_STUB cti_op_throw_syntax_error(STUB_ARGS_DECLARATION); void* JIT_STUB cti_op_call_arityCheck(STUB_ARGS_DECLARATION); void* JIT_STUB cti_op_construct_arityCheck(STUB_ARGS_DECLARATION); void* JIT_STUB cti_op_call_jitCompile(STUB_ARGS_DECLARATION); diff --git a/JavaScriptCore/parser/Nodes.h b/JavaScriptCore/parser/Nodes.h index f2a7c1e..6930f63 100644 --- a/JavaScriptCore/parser/Nodes.h +++ b/JavaScriptCore/parser/Nodes.h @@ -269,9 +269,8 @@ namespace JSC { uint16_t endOffset() const { return m_endOffset; } protected: - RegisterID* emitThrowError(BytecodeGenerator&, bool isReferenceError, const char* message); - RegisterID* emitThrowError(BytecodeGenerator&, bool isReferenceError, const char* message, const UString&); - RegisterID* emitThrowError(BytecodeGenerator&, bool isReferenceError, const char* message, const Identifier&); + RegisterID* emitThrowReferenceError(BytecodeGenerator&, const UString& message); + RegisterID* emitThrowSyntaxError(BytecodeGenerator&, const UString& message); private: uint32_t m_divot; diff --git a/JavaScriptCore/runtime/Error.cpp b/JavaScriptCore/runtime/Error.cpp index fd97beb..227e9ec 100644 --- a/JavaScriptCore/runtime/Error.cpp +++ b/JavaScriptCore/runtime/Error.cpp @@ -38,9 +38,6 @@ namespace JSC { static const char* linePropertyName = "line"; static const char* sourceIdPropertyName = "sourceId"; static const char* sourceURLPropertyName = "sourceURL"; -static const char* expressionBeginOffsetPropertyName = "expressionBeginOffset"; -static const char* expressionCaretOffsetPropertyName = "expressionCaretOffset"; -static const char* expressionEndOffsetPropertyName = "expressionEndOffset"; JSObject* createError(JSGlobalObject* globalObject, const UString& message) { @@ -119,7 +116,7 @@ JSObject* createURIError(ExecState* exec, const UString& message) return createURIError(exec->lexicalGlobalObject(), message); } -static void addErrorSourceInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source) +JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source) { intptr_t sourceID = source.provider()->asID(); const UString& sourceURL = source.provider()->url(); @@ -130,26 +127,7 @@ static void addErrorSourceInfo(JSGlobalData* globalData, JSObject* error, int li error->putWithAttributes(globalData, Identifier(globalData, sourceIdPropertyName), jsNumber((double)sourceID), ReadOnly | DontDelete); if (!sourceURL.isNull()) error->putWithAttributes(globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete); -} - -static void addErrorDivotInfo(JSGlobalData* globalData, JSObject* error, int divotPoint, int startOffset, int endOffset, bool withCaret) -{ - error->putWithAttributes(globalData, Identifier(globalData, expressionBeginOffsetPropertyName), jsNumber(divotPoint - startOffset), ReadOnly | DontDelete); - error->putWithAttributes(globalData, Identifier(globalData, expressionEndOffsetPropertyName), jsNumber(divotPoint + endOffset), ReadOnly | DontDelete); - if (withCaret) - error->putWithAttributes(globalData, Identifier(globalData, expressionCaretOffsetPropertyName), jsNumber(divotPoint), ReadOnly | DontDelete); -} - -JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source) -{ - addErrorSourceInfo(globalData, error, line, source); - return error; -} -JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source, int divotPoint, int startOffset, int endOffset, bool withCaret) -{ - addErrorSourceInfo(globalData, error, line, source); - addErrorDivotInfo(globalData, error, divotPoint, startOffset, endOffset, withCaret); return error; } @@ -158,19 +136,11 @@ JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceC return addErrorInfo(&exec->globalData(), error, line, source); } -JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source, int divotPoint, int startOffset, int endOffset, bool withCaret) -{ - return addErrorInfo(&exec->globalData(), error, line, source, divotPoint, startOffset, endOffset, withCaret); -} - bool hasErrorInfo(ExecState* exec, JSObject* error) { return error->hasProperty(exec, Identifier(exec, linePropertyName)) || error->hasProperty(exec, Identifier(exec, sourceIdPropertyName)) - || error->hasProperty(exec, Identifier(exec, sourceURLPropertyName)) - || error->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) - || error->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) - || error->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName)); + || error->hasProperty(exec, Identifier(exec, sourceURLPropertyName)); } JSValue throwError(ExecState* exec, JSValue error) diff --git a/JavaScriptCore/runtime/Error.h b/JavaScriptCore/runtime/Error.h index bfde7dc..c0f9d32 100644 --- a/JavaScriptCore/runtime/Error.h +++ b/JavaScriptCore/runtime/Error.h @@ -56,10 +56,8 @@ namespace JSC { // Methods to add bool hasErrorInfo(ExecState*, JSObject* error); JSObject* addErrorInfo(JSGlobalData*, JSObject* error, int line, const SourceCode&); - JSObject* addErrorInfo(JSGlobalData*, JSObject* error, int line, const SourceCode&, int divotPoint, int startOffset, int endOffset, bool withCaret = true); // ExecState wrappers. JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&); - JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&, int divotPoint, int startOffset, int endOffset, bool withCaret = true); // Methods to throw Errors. JSValue throwError(ExecState*, JSValue); diff --git a/JavaScriptCore/runtime/ErrorInstance.cpp b/JavaScriptCore/runtime/ErrorInstance.cpp index 740e20e..0f3153c 100644 --- a/JavaScriptCore/runtime/ErrorInstance.cpp +++ b/JavaScriptCore/runtime/ErrorInstance.cpp @@ -27,12 +27,14 @@ const ClassInfo ErrorInstance::info = { "Error", 0, 0, 0 }; ErrorInstance::ErrorInstance(JSGlobalData* globalData, NonNullPassRefPtr<Structure> structure) : JSObject(structure) + , m_appendSourceToMessage(false) { putDirect(globalData->propertyNames->message, jsString(globalData, "")); } ErrorInstance::ErrorInstance(JSGlobalData* globalData, NonNullPassRefPtr<Structure> structure, const UString& message) : JSObject(structure) + , m_appendSourceToMessage(false) { putDirect(globalData->propertyNames->message, jsString(globalData, message)); } diff --git a/JavaScriptCore/runtime/ErrorInstance.h b/JavaScriptCore/runtime/ErrorInstance.h index a49cc3c..b3bebec 100644 --- a/JavaScriptCore/runtime/ErrorInstance.h +++ b/JavaScriptCore/runtime/ErrorInstance.h @@ -34,9 +34,18 @@ namespace JSC { static ErrorInstance* create(JSGlobalData*, NonNullPassRefPtr<Structure>, const UString&); static ErrorInstance* create(ExecState* exec, NonNullPassRefPtr<Structure>, JSValue message); + + bool appendSourceToMessage() { return m_appendSourceToMessage; } + void setAppendSourceToMessage() { m_appendSourceToMessage = true; } + void clearAppendSourceToMessage() { m_appendSourceToMessage = false; } + + virtual bool isErrorInstance() const { return true; } + protected: explicit ErrorInstance(JSGlobalData*, NonNullPassRefPtr<Structure>); explicit ErrorInstance(JSGlobalData*, NonNullPassRefPtr<Structure>, const UString&); + + bool m_appendSourceToMessage; }; } // namespace JSC diff --git a/JavaScriptCore/runtime/ExceptionHelpers.cpp b/JavaScriptCore/runtime/ExceptionHelpers.cpp index 5fbaa18..1ef264c 100644 --- a/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -31,6 +31,7 @@ #include "CodeBlock.h" #include "CallFrame.h" +#include "ErrorInstance.h" #include "JSGlobalObjectFunctions.h" #include "JSObject.h" #include "JSNotAnObject.h" @@ -52,7 +53,7 @@ public: virtual UString toString(ExecState*) const { return "JavaScript execution exceeded timeout."; } }; -JSValue createInterruptedExecutionException(JSGlobalData* globalData) +JSObject* createInterruptedExecutionException(JSGlobalData* globalData) { return new (globalData) InterruptedExecutionError(globalData); } @@ -69,7 +70,7 @@ public: virtual UString toString(ExecState*) const { return "JavaScript execution terminated."; } }; -JSValue createTerminatedExecutionException(JSGlobalData* globalData) +JSObject* createTerminatedExecutionException(JSGlobalData* globalData) { return new (globalData) TerminatedExecutionError(globalData); } @@ -84,106 +85,45 @@ JSObject* createStackOverflowError(JSGlobalObject* globalObject) return createRangeError(globalObject, "Maximum call stack size exceeded."); } -JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, unsigned bytecodeOffset, CodeBlock* codeBlock) +JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident) { - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); UString message(makeUString("Can't find variable: ", ident.ustring())); - JSObject* exception = addErrorInfo(exec, createReferenceError(exec, message), line, codeBlock->ownerExecutable()->source(), divotPoint, startOffset, endOffset); - return exception; + return createReferenceError(exec, message); } -static UString createErrorMessage(ExecState* exec, CodeBlock* codeBlock, int, int expressionStart, int expressionStop, JSValue value, UString error) +JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value) { - if (!expressionStop || expressionStart > codeBlock->source()->length()) - return makeUString(value.toString(exec), " is ", error); - if (expressionStart < expressionStop) - return makeUString("Result of expression '", codeBlock->source()->getRange(expressionStart, expressionStop), "' [", value.toString(exec), "] is ", error, "."); - - // No range information, so give a few characters of context - const UChar* data = codeBlock->source()->data(); - int dataLength = codeBlock->source()->length(); - int start = expressionStart; - int stop = expressionStart; - // Get up to 20 characters of context to the left and right of the divot, clamping to the line. - // then strip whitespace. - while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n') - start--; - while (start < (expressionStart - 1) && isStrWhiteSpace(data[start])) - start++; - while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n') - stop++; - while (stop > expressionStart && isStrWhiteSpace(data[stop])) - stop--; - return makeUString("Result of expression near '...", codeBlock->source()->getRange(start, stop), "...' [", value.toString(exec), "] is ", error, "."); -} - -JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock) -{ - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, makeUString("not a valid argument for '", op, "'")); - JSObject* exception = addErrorInfo(exec, createTypeError(exec, errorMessage), line, codeBlock->ownerExecutable()->source(), divotPoint, startOffset, endOffset); + UString errorMessage = makeUString("'", value.toString(exec), "' is not a valid argument for '", op, "'"); + JSObject* exception = createTypeError(exec, errorMessage); + ASSERT(exception->isErrorInstance()); + static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); return exception; } -JSObject* createNotAConstructorError(ExecState* exec, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock) +JSObject* createNotAConstructorError(ExecState* exec, JSValue value) { - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - - // We're in a "new" expression, so we need to skip over the "new.." part - int startPoint = divotPoint - (startOffset ? startOffset - 4 : 0); // -4 for "new " - const UChar* data = codeBlock->source()->data(); - while (startPoint < divotPoint && isStrWhiteSpace(data[startPoint])) - startPoint++; - - UString errorMessage = createErrorMessage(exec, codeBlock, line, startPoint, divotPoint, value, "not a constructor"); - JSObject* exception = addErrorInfo(exec, createTypeError(exec, errorMessage), line, codeBlock->ownerExecutable()->source(), divotPoint, startOffset, endOffset); + UString errorMessage = makeUString("'", value.toString(exec), "' is not a constructor"); + JSObject* exception = createTypeError(exec, errorMessage); + ASSERT(exception->isErrorInstance()); + static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); return exception; } -JSValue createNotAFunctionError(ExecState* exec, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock) +JSObject* createNotAFunctionError(ExecState* exec, JSValue value) { - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, value, "not a function"); - JSObject* exception = addErrorInfo(exec, createTypeError(exec, errorMessage), line, codeBlock->ownerExecutable()->source(), divotPoint, startOffset, endOffset); + UString errorMessage = makeUString("'", value.toString(exec), "' is not a function"); + JSObject* exception = createTypeError(exec, errorMessage); + ASSERT(exception->isErrorInstance()); + static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); return exception; } -JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState* exec, bool isNull) +JSObject* createNotAnObjectError(ExecState* exec, JSValue value) { - return new (exec) JSNotAnObjectErrorStub(exec, isNull); -} - -JSObject* createNotAnObjectError(ExecState* exec, JSNotAnObjectErrorStub* error, unsigned bytecodeOffset, CodeBlock* codeBlock) -{ - // Both op_create_this and op_instanceof require a use of op_get_by_id to get - // the prototype property from an object. The exception messages for exceptions - // thrown by these instances op_get_by_id need to reflect this. - OpcodeID followingOpcodeID; - if (codeBlock->getByIdExceptionInfoForBytecodeOffset(exec, bytecodeOffset, followingOpcodeID)) { - ASSERT(followingOpcodeID == op_create_this || followingOpcodeID == op_instanceof); - if (followingOpcodeID == op_create_this) - return createNotAConstructorError(exec, error->isNull() ? jsNull() : jsUndefined(), bytecodeOffset, codeBlock); - return createInvalidParamError(exec, "instanceof", error->isNull() ? jsNull() : jsUndefined(), bytecodeOffset, codeBlock); - } - - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, error->isNull() ? jsNull() : jsUndefined(), "not an object"); - JSObject* exception = addErrorInfo(exec, createTypeError(exec, errorMessage), line, codeBlock->ownerExecutable()->source(), divotPoint, startOffset, endOffset); + UString errorMessage = makeUString("'", value.toString(exec), "' is not an object"); + JSObject* exception = createTypeError(exec, errorMessage); + ASSERT(exception->isErrorInstance()); + static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); return exception; } diff --git a/JavaScriptCore/runtime/ExceptionHelpers.h b/JavaScriptCore/runtime/ExceptionHelpers.h index a7b2ca7..7edffad 100644 --- a/JavaScriptCore/runtime/ExceptionHelpers.h +++ b/JavaScriptCore/runtime/ExceptionHelpers.h @@ -43,16 +43,15 @@ namespace JSC { class Node; struct Instruction; - JSValue createInterruptedExecutionException(JSGlobalData*); - JSValue createTerminatedExecutionException(JSGlobalData*); + JSObject* createInterruptedExecutionException(JSGlobalData*); + JSObject* createTerminatedExecutionException(JSGlobalData*); JSObject* createStackOverflowError(ExecState*); JSObject* createStackOverflowError(JSGlobalObject*); - JSValue createUndefinedVariableError(ExecState*, const Identifier&, unsigned bytecodeOffset, CodeBlock*); - JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState*, bool isNull); - JSObject* createInvalidParamError(ExecState*, const char* op, JSValue, unsigned bytecodeOffset, CodeBlock*); - JSObject* createNotAConstructorError(ExecState*, JSValue, unsigned bytecodeOffset, CodeBlock*); - JSValue createNotAFunctionError(ExecState*, JSValue, unsigned bytecodeOffset, CodeBlock*); - JSObject* createNotAnObjectError(ExecState*, JSNotAnObjectErrorStub*, unsigned bytecodeOffset, CodeBlock*); + JSObject* createUndefinedVariableError(ExecState*, const Identifier&); + JSObject* createNotAnObjectError(ExecState*, JSValue); + JSObject* createInvalidParamError(ExecState*, const char* op, JSValue); + JSObject* createNotAConstructorError(ExecState*, JSValue); + JSObject* createNotAFunctionError(ExecState*, JSValue); JSObject* createErrorForInvalidGlobalAssignment(ExecState*, const UString&); JSObject* throwOutOfMemoryError(ExecState*); diff --git a/JavaScriptCore/runtime/JSFunction.cpp b/JavaScriptCore/runtime/JSFunction.cpp index 0697fc3..ba89d04 100644 --- a/JavaScriptCore/runtime/JSFunction.cpp +++ b/JavaScriptCore/runtime/JSFunction.cpp @@ -45,9 +45,7 @@ namespace JSC { #if ENABLE(JIT) EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec) { - CodeBlock* codeBlock = exec->callerFrame()->codeBlock(); - unsigned vPCIndex = codeBlock->bytecodeOffset(exec, exec->returnPC()); - return throwVMError(exec, createNotAConstructorError(exec, exec->callee(), vPCIndex, codeBlock)); + return throwVMError(exec, createNotAConstructorError(exec, exec->callee())); } #endif @@ -284,6 +282,10 @@ bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& pro void JSFunction::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { if (!isHostFunction() && (mode == IncludeDontEnumProperties)) { + // Make sure prototype has been reified. + PropertySlot slot; + getOwnPropertySlot(exec, exec->propertyNames().prototype, slot); + propertyNames.add(exec->propertyNames().arguments); propertyNames.add(exec->propertyNames().callee); propertyNames.add(exec->propertyNames().caller); @@ -298,6 +300,12 @@ void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue va Base::put(exec, propertyName, value, slot); return; } + if (propertyName == exec->propertyNames().prototype) { + // Make sure prototype has been reified, such that it can only be overwritten + // following the rules set out in ECMA-262 8.12.9. + PropertySlot slot; + getOwnPropertySlot(exec, propertyName, slot); + } if (jsExecutable()->isStrictMode()) { if (propertyName == exec->propertyNames().arguments) { throwTypeError(exec, StrictModeArgumentsAccessError); diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp index 1404ddf..58b844c 100644 --- a/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/JavaScriptCore/runtime/JSGlobalData.cpp @@ -127,7 +127,6 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull())) , strictEvalActivationStructure(StrictEvalActivation::createStructure(jsNull())) , stringStructure(JSString::createStructure(jsNull())) - , notAnObjectErrorStubStructure(JSNotAnObjectErrorStub::createStructure(jsNull())) , notAnObjectStructure(JSNotAnObject::createStructure(jsNull())) , propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull())) , getterSetterStructure(GetterSetter::createStructure(jsNull())) diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h index 775d026..153a4e5 100644 --- a/JavaScriptCore/runtime/JSGlobalData.h +++ b/JavaScriptCore/runtime/JSGlobalData.h @@ -147,7 +147,6 @@ namespace JSC { RefPtr<Structure> staticScopeStructure; RefPtr<Structure> strictEvalActivationStructure; RefPtr<Structure> stringStructure; - RefPtr<Structure> notAnObjectErrorStubStructure; RefPtr<Structure> notAnObjectStructure; RefPtr<Structure> propertyNameIteratorStructure; RefPtr<Structure> getterSetterStructure; diff --git a/JavaScriptCore/runtime/JSNotAnObject.cpp b/JavaScriptCore/runtime/JSNotAnObject.cpp index f4764e2..e01b401 100644 --- a/JavaScriptCore/runtime/JSNotAnObject.cpp +++ b/JavaScriptCore/runtime/JSNotAnObject.cpp @@ -39,91 +39,84 @@ ASSERT_CLASS_FITS_IN_CELL(JSNotAnObject); // JSValue methods JSValue JSNotAnObject::toPrimitive(ExecState* exec, PreferredPrimitiveType) const { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); - return m_exception; + ASSERT_UNUSED(exec, exec->hadException()); + return jsNumber(0); } bool JSNotAnObject::getPrimitiveNumber(ExecState* exec, double&, JSValue&) { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); return false; } bool JSNotAnObject::toBoolean(ExecState* exec) const { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); return false; } double JSNotAnObject::toNumber(ExecState* exec) const { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); return NaN; } UString JSNotAnObject::toString(ExecState* exec) const { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); return ""; } JSObject* JSNotAnObject::toObject(ExecState* exec) const { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); - return m_exception; -} - -// Marking -void JSNotAnObject::markChildren(MarkStack& markStack) -{ - JSObject::markChildren(markStack); - markStack.append(m_exception); + ASSERT_UNUSED(exec, exec->hadException()); + return const_cast<JSNotAnObject*>(this); } // JSObject methods bool JSNotAnObject::getOwnPropertySlot(ExecState* exec, const Identifier&, PropertySlot&) { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); return false; } bool JSNotAnObject::getOwnPropertySlot(ExecState* exec, unsigned, PropertySlot&) { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); return false; } bool JSNotAnObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier&, PropertyDescriptor&) { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); return false; } void JSNotAnObject::put(ExecState* exec, const Identifier& , JSValue, PutPropertySlot&) { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); } void JSNotAnObject::put(ExecState* exec, unsigned, JSValue) { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); } bool JSNotAnObject::deleteProperty(ExecState* exec, const Identifier&) { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); return false; } bool JSNotAnObject::deleteProperty(ExecState* exec, unsigned) { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); return false; } void JSNotAnObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray&, EnumerationMode) { - ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + ASSERT_UNUSED(exec, exec->hadException()); } } // namespace JSC diff --git a/JavaScriptCore/runtime/JSNotAnObject.h b/JavaScriptCore/runtime/JSNotAnObject.h index 339d41f..9f527cf 100644 --- a/JavaScriptCore/runtime/JSNotAnObject.h +++ b/JavaScriptCore/runtime/JSNotAnObject.h @@ -33,30 +33,13 @@ namespace JSC { - class JSNotAnObjectErrorStub : public JSObject { - public: - JSNotAnObjectErrorStub(ExecState* exec, bool isNull) - : JSObject(exec->globalData().notAnObjectErrorStubStructure) - , m_isNull(isNull) - { - } - - bool isNull() const { return m_isNull; } - - private: - virtual bool isNotAnObjectErrorStub() const { return true; } - - bool m_isNull; - }; - // This unholy class is used to allow us to avoid multiple exception checks // in certain SquirrelFish bytecodes -- effectively it just silently consumes // any operations performed on the result of a failed toObject call. class JSNotAnObject : public JSObject { public: - JSNotAnObject(ExecState* exec, JSNotAnObjectErrorStub* exception) + JSNotAnObject(ExecState* exec) : JSObject(exec->globalData().notAnObjectStructure) - , m_exception(exception) { } @@ -67,7 +50,7 @@ namespace JSC { private: - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags; + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags; // JSValue methods virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; @@ -77,9 +60,6 @@ namespace JSC { virtual UString toString(ExecState*) const; virtual JSObject* toObject(ExecState*) const; - // Marking - virtual void markChildren(MarkStack&); - // JSObject methods virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); @@ -92,8 +72,6 @@ namespace JSC { virtual bool deleteProperty(ExecState*, unsigned propertyName); virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); - - JSNotAnObjectErrorStub* m_exception; }; } // namespace JSC diff --git a/JavaScriptCore/runtime/JSObject.h b/JavaScriptCore/runtime/JSObject.h index f484ce4..803abfd 100644 --- a/JavaScriptCore/runtime/JSObject.h +++ b/JavaScriptCore/runtime/JSObject.h @@ -208,8 +208,8 @@ namespace JSC { virtual bool isGlobalObject() const { return false; } virtual bool isVariableObject() const { return false; } virtual bool isActivationObject() const { return false; } - virtual bool isNotAnObjectErrorStub() const { return false; } virtual bool isStrictModeFunction() const { return false; } + virtual bool isErrorInstance() const { return false; } virtual ComplType exceptionType() const { return Throw; } diff --git a/JavaScriptCore/runtime/JSValue.cpp b/JavaScriptCore/runtime/JSValue.cpp index 2a23a79..f4662db 100644 --- a/JavaScriptCore/runtime/JSValue.cpp +++ b/JavaScriptCore/runtime/JSValue.cpp @@ -62,10 +62,10 @@ JSObject* JSValue::toObjectSlowCase(ExecState* exec) const return constructNumber(exec, asValue()); if (isTrue() || isFalse()) return constructBooleanFromImmediateBoolean(exec, asValue()); + ASSERT(isUndefinedOrNull()); - JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, isNull()); - throwError(exec, exception); - return new (exec) JSNotAnObject(exec, exception); + throwError(exec, createNotAnObjectError(exec, *this)); + return new (exec) JSNotAnObject(exec); } JSObject* JSValue::toThisObjectSlowCase(ExecState* exec) const @@ -87,10 +87,10 @@ JSObject* JSValue::synthesizeObject(ExecState* exec) const return constructNumber(exec, asValue()); if (isBoolean()) return constructBooleanFromImmediateBoolean(exec, asValue()); - - JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, isNull()); - throwError(exec, exception); - return new (exec) JSNotAnObject(exec, exception); + + ASSERT(isUndefinedOrNull()); + throwError(exec, createNotAnObjectError(exec, *this)); + return new (exec) JSNotAnObject(exec); } JSObject* JSValue::synthesizePrototype(ExecState* exec) const @@ -101,9 +101,9 @@ JSObject* JSValue::synthesizePrototype(ExecState* exec) const if (isBoolean()) return exec->lexicalGlobalObject()->booleanPrototype(); - JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, isNull()); - throwError(exec, exception); - return new (exec) JSNotAnObject(exec, exception); + ASSERT(isUndefinedOrNull()); + throwError(exec, createNotAnObjectError(exec, *this)); + return new (exec) JSNotAnObject(exec); } #ifndef NDEBUG diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h index cb732f3..e1fdc60 100644 --- a/JavaScriptCore/wtf/Platform.h +++ b/JavaScriptCore/wtf/Platform.h @@ -188,6 +188,18 @@ #define WTF_CPU_SPARC 1 #endif +/* CPU(S390X) - S390 64-bit */ +#if defined(__s390x__) +#define WTF_CPU_S390X 1 +#define WTF_CPU_BIG_ENDIAN 1 +#endif + +/* CPU(S390) - S390 32-bit */ +#if defined(__s390__) +#define WTF_CPU_S390 1 +#define WTF_CPU_BIG_ENDIAN 1 +#endif + /* CPU(X86) - i386 / x86 32-bit */ #if defined(__i386__) \ || defined(i386) \ @@ -594,6 +606,7 @@ #define HAVE_READLINE 1 #define HAVE_RUNLOOP_TIMER 1 #define ENABLE_FULLSCREEN_API 1 +#define ENABLE_SMOOTH_SCROLLING 1 #endif /* PLATFORM(MAC) && !PLATFORM(IOS) */ #if PLATFORM(MAC) @@ -941,6 +954,7 @@ || (CPU(IA64) && !CPU(IA64_32)) \ || CPU(ALPHA) \ || CPU(SPARC64) \ + || CPU(S390X) \ || CPU(PPC64) #define WTF_USE_JSVALUE64 1 #else @@ -1126,3 +1140,4 @@ #endif #endif /* WTF_Platform_h */ + diff --git a/JavaScriptCore/wtf/text/CString.cpp b/JavaScriptCore/wtf/text/CString.cpp index c048a1b..db6443f 100644 --- a/JavaScriptCore/wtf/text/CString.cpp +++ b/JavaScriptCore/wtf/text/CString.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,12 +27,15 @@ #include "config.h" #include "CString.h" -using std::min; +using namespace std; namespace WTF { CString::CString(const char* str) { + if (!str) + return; + init(str, strlen(str)); } @@ -45,7 +48,10 @@ void CString::init(const char* str, size_t length) { if (!str) return; - + + if (length >= numeric_limits<size_t>::max()) + CRASH(); + m_buffer = CStringBuffer::create(length + 1); memcpy(m_buffer->mutableData(), str, length); m_buffer->mutableData()[length] = '\0'; @@ -61,6 +67,9 @@ char* CString::mutableData() CString CString::newUninitialized(size_t length, char*& characterBuffer) { + if (length >= numeric_limits<size_t>::max()) + CRASH(); + CString result; result.m_buffer = CStringBuffer::create(length + 1); char* bytes = result.m_buffer->mutableData(); @@ -73,11 +82,11 @@ void CString::copyBufferIfNeeded() { if (!m_buffer || m_buffer->hasOneRef()) return; - - int len = m_buffer->length(); - RefPtr<CStringBuffer> m_temp = m_buffer; - m_buffer = CStringBuffer::create(len); - memcpy(m_buffer->mutableData(), m_temp->data(), len); + + RefPtr<CStringBuffer> buffer = m_buffer.release(); + size_t length = buffer->length(); + m_buffer = CStringBuffer::create(length); + memcpy(m_buffer->mutableData(), buffer->data(), length); } bool operator==(const CString& a, const CString& b) diff --git a/JavaScriptCore/wtf/text/StringImpl.cpp b/JavaScriptCore/wtf/text/StringImpl.cpp index f4b2f05..1c4de66 100644 --- a/JavaScriptCore/wtf/text/StringImpl.cpp +++ b/JavaScriptCore/wtf/text/StringImpl.cpp @@ -96,9 +96,9 @@ PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned leng return empty(); UChar* data; - PassRefPtr<StringImpl> string = createUninitialized(length, data); + RefPtr<StringImpl> string = createUninitialized(length, data); memcpy(data, characters, length * sizeof(UChar)); - return string; + return string.release(); } PassRefPtr<StringImpl> StringImpl::create(const char* characters, unsigned length) @@ -107,19 +107,22 @@ PassRefPtr<StringImpl> StringImpl::create(const char* characters, unsigned lengt return empty(); UChar* data; - PassRefPtr<StringImpl> string = createUninitialized(length, data); + RefPtr<StringImpl> string = createUninitialized(length, data); for (unsigned i = 0; i != length; ++i) { unsigned char c = characters[i]; data[i] = c; } - return string; + return string.release(); } PassRefPtr<StringImpl> StringImpl::create(const char* string) { if (!string) return empty(); - return create(string, strlen(string)); + size_t length = strlen(string); + if (length > numeric_limits<unsigned>::max()) + CRASH(); + return create(string, length); } PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer) @@ -205,7 +208,10 @@ PassRefPtr<StringImpl> StringImpl::lower() if (noUpper && !(ored & ~0x7F)) return this; + if (m_length > static_cast<unsigned>(numeric_limits<int32_t>::max())) + CRASH(); int32_t length = m_length; + UChar* data; RefPtr<StringImpl> newImpl = createUninitialized(m_length, data); @@ -236,7 +242,10 @@ PassRefPtr<StringImpl> StringImpl::upper() // but in empirical testing, few actual calls to upper() are no-ops, so // it wouldn't be worth the extra time for pre-scanning. UChar* data; - PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + RefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + + if (m_length > static_cast<unsigned>(numeric_limits<int32_t>::max())) + CRASH(); int32_t length = m_length; // Do a faster loop for the case where all the characters are ASCII. @@ -247,7 +256,7 @@ PassRefPtr<StringImpl> StringImpl::upper() data[i] = toASCIIUpper(c); } if (!(ored & ~0x7F)) - return newImpl; + return newImpl.release(); // Do a slower implementation for cases that include non-ASCII characters. bool error; @@ -258,45 +267,47 @@ PassRefPtr<StringImpl> StringImpl::upper() Unicode::toUpper(data, realLength, m_data, m_length, &error); if (error) return this; - return newImpl; + return newImpl.release(); } -PassRefPtr<StringImpl> StringImpl::secure(UChar aChar) +PassRefPtr<StringImpl> StringImpl::secure(UChar character) { UChar* data; - PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); - int32_t length = m_length; - for (int i = 0; i < length; ++i) - data[i] = aChar; - return newImpl; + RefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + for (unsigned i = 0; i < m_length; ++i) + data[i] = character; + return newImpl.release(); } PassRefPtr<StringImpl> StringImpl::foldCase() { UChar* data; - PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + RefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + + if (m_length > static_cast<unsigned>(numeric_limits<int32_t>::max())) + CRASH(); int32_t length = m_length; // Do a faster loop for the case where all the characters are ASCII. UChar ored = 0; - for (int i = 0; i < length; i++) { + for (int32_t i = 0; i < length; i++) { UChar c = m_data[i]; ored |= c; data[i] = toASCIILower(c); } if (!(ored & ~0x7F)) - return newImpl; + return newImpl.release(); // Do a slower implementation for cases that include non-ASCII characters. bool error; int32_t realLength = Unicode::foldCase(data, length, m_data, m_length, &error); if (!error && realLength == length) - return newImpl; + return newImpl.release(); newImpl = createUninitialized(realLength, data); Unicode::foldCase(data, realLength, m_data, m_length, &error); if (error) return this; - return newImpl; + return newImpl.release(); } PassRefPtr<StringImpl> StringImpl::stripWhiteSpace() @@ -517,7 +528,10 @@ size_t StringImpl::find(const char* matchString, unsigned index) // Check for null or empty string to match against if (!matchString) return notFound; - unsigned matchLength = strlen(matchString); + size_t matchStringLength = strlen(matchString); + if (matchStringLength > numeric_limits<unsigned>::max()) + CRASH(); + unsigned matchLength = matchStringLength; if (!matchLength) return min(index, length()); @@ -563,7 +577,10 @@ size_t StringImpl::findIgnoringCase(const char* matchString, unsigned index) // Check for null or empty string to match against if (!matchString) return notFound; - unsigned matchLength = strlen(matchString); + size_t matchStringLength = strlen(matchString); + if (matchStringLength > numeric_limits<unsigned>::max()) + CRASH(); + unsigned matchLength = matchStringLength; if (!matchLength) return min(index, length()); @@ -761,7 +778,7 @@ PassRefPtr<StringImpl> StringImpl::replace(UChar oldC, UChar newC) return this; UChar* data; - PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + RefPtr<StringImpl> newImpl = createUninitialized(m_length, data); for (i = 0; i != m_length; ++i) { UChar ch = m_data[i]; @@ -769,7 +786,7 @@ PassRefPtr<StringImpl> StringImpl::replace(UChar oldC, UChar newC) ch = newC; data[i] = ch; } - return newImpl; + return newImpl.release(); } PassRefPtr<StringImpl> StringImpl::replace(unsigned position, unsigned lengthToReplace, StringImpl* str) @@ -784,14 +801,14 @@ PassRefPtr<StringImpl> StringImpl::replace(unsigned position, unsigned lengthToR if ((length() - lengthToReplace) >= (numeric_limits<unsigned>::max() - lengthToInsert)) CRASH(); - PassRefPtr<StringImpl> newImpl = + RefPtr<StringImpl> newImpl = createUninitialized(length() - lengthToReplace + lengthToInsert, data); memcpy(data, characters(), position * sizeof(UChar)); if (str) memcpy(data + position, str->characters(), lengthToInsert * sizeof(UChar)); memcpy(data + position + lengthToInsert, characters() + position + lengthToReplace, (length() - position - lengthToReplace) * sizeof(UChar)); - return newImpl; + return newImpl.release(); } PassRefPtr<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacement) @@ -824,7 +841,7 @@ PassRefPtr<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacemen newSize += replaceSize; UChar* data; - PassRefPtr<StringImpl> newImpl = createUninitialized(newSize, data); + RefPtr<StringImpl> newImpl = createUninitialized(newSize, data); // Construct the new data size_t srcSegmentEnd; @@ -846,7 +863,7 @@ PassRefPtr<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacemen ASSERT(dstOffset + srcSegmentLength == newImpl->length()); - return newImpl; + return newImpl.release(); } PassRefPtr<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* replacement) @@ -882,7 +899,7 @@ PassRefPtr<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* repl newSize += matchCount * repStrLength; UChar* data; - PassRefPtr<StringImpl> newImpl = createUninitialized(newSize, data); + RefPtr<StringImpl> newImpl = createUninitialized(newSize, data); // Construct the new data size_t srcSegmentEnd; @@ -904,7 +921,7 @@ PassRefPtr<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* repl ASSERT(dstOffset + srcSegmentLength == newImpl->length()); - return newImpl; + return newImpl.release(); } bool equal(const StringImpl* a, const StringImpl* b) @@ -1020,9 +1037,11 @@ PassRefPtr<StringImpl> StringImpl::adopt(StringBuffer& buffer) PassRefPtr<StringImpl> StringImpl::createWithTerminatingNullCharacter(const StringImpl& string) { // Use createUninitialized instead of 'new StringImpl' so that the string and its buffer - // get allocated in a single malloc block. + // get allocated in a single memory block. UChar* data; - int length = string.m_length; + unsigned length = string.m_length; + if (length >= numeric_limits<unsigned>::max()) + CRASH(); RefPtr<StringImpl> terminatedString = createUninitialized(length + 1, data); memcpy(data, string.m_data, length * sizeof(UChar)); data[length] = 0; diff --git a/JavaScriptCore/wtf/text/TextPosition.h b/JavaScriptCore/wtf/text/TextPosition.h new file mode 100644 index 0000000..63dc594 --- /dev/null +++ b/JavaScriptCore/wtf/text/TextPosition.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TextPosition_h +#define TextPosition_h + +#include <wtf/Assertions.h> + +namespace WTF { + +/* + * Text Position + * + * TextPosition structure specifies coordinates within an text resource. It is used mostly + * for saving script source position. + * + * Later TextPosition0 and TextPosition1 and both number types can be merged together quite easily. + * + * 0-based and 1-based + * + * Line and column numbers could be interpreted as zero-based or 1-based. Since + * both practices coexist in WebKit source base, 'int' type should be replaced with + * a dedicated wrapper types, so that compiler helped us with this ambiguity. + * + * Here we introduce 2 types of numbers: ZeroBasedNumber and OneBasedNumber and + * 2 corresponding types of TextPosition structure. While only one type ought to be enough, + * this is done to keep transition to the new types as transparent as possible: + * e.g. in areas where 0-based integers are used, TextPosition0 should be introduced. This + * way all changes will remain trackable. + * + * Later both number types can be merged in one type quite easily. + * + * For type safety and for the future type merge it is important that all operations in API + * that accept or return integer have a name explicitly defining base of integer. For this reason + * int-receiving constructors are hidden from API. + */ + +template<typename NUMBER> +class TextPosition { +public: + TextPosition(NUMBER line, NUMBER column) + : m_line(line) + , m_column(column) + { + } + TextPosition() {} + + // A 'minimum' value of position, used as a default value. + static TextPosition<NUMBER> minimumPosition() { return TextPosition<NUMBER>(NUMBER::base(), NUMBER::base()); } + + // A value with line value less than a minimum; used as an impossible position. + static TextPosition<NUMBER> belowRangePosition() { return TextPosition<NUMBER>(NUMBER::belowBase(), NUMBER::base()); } + + NUMBER m_line; + NUMBER m_column; +}; + +class OneBasedNumber; + +// An int wrapper that always reminds you that the number should be 0-based +class ZeroBasedNumber { +public: + static ZeroBasedNumber fromZeroBasedInt(int zeroBasedInt) { return ZeroBasedNumber(zeroBasedInt); } + + ZeroBasedNumber() {} + + int zeroBasedInt() const { return m_value; } + + OneBasedNumber convertToOneBased() const; + + static ZeroBasedNumber base() { return 0; } + static ZeroBasedNumber belowBase() { return -1; } + +private: + ZeroBasedNumber(int value) : m_value(value) {} + int m_value; +}; + +// An int wrapper that always reminds you that the number should be 1-based +class OneBasedNumber { +public: + static OneBasedNumber fromOneBasedInt(int oneBasedInt) { return OneBasedNumber(oneBasedInt); } + OneBasedNumber() {} + + int oneBasedInt() const { return m_value; } + int convertAsZeroBasedInt() const { return m_value - 1; } + ZeroBasedNumber convertToZeroBased() const { return ZeroBasedNumber::fromZeroBasedInt(m_value - 1); } + + static OneBasedNumber base() { return 1; } + static OneBasedNumber belowBase() { return 0; } + +private: + OneBasedNumber(int value) : m_value(value) {} + int m_value; +}; + +typedef TextPosition<ZeroBasedNumber> TextPosition0; +typedef TextPosition<OneBasedNumber> TextPosition1; + +inline TextPosition0 toZeroBasedTextPosition(const TextPosition1& position) +{ + return TextPosition0(position.m_line.convertToZeroBased(), position.m_column.convertToZeroBased()); +} + +inline TextPosition1 toOneBasedTextPosition(const TextPosition0& position) +{ + return TextPosition1(position.m_line.convertToOneBased(), position.m_column.convertToOneBased()); +} + +inline OneBasedNumber ZeroBasedNumber::convertToOneBased() const +{ + return OneBasedNumber::fromOneBasedInt(m_value + 1); +} + +} + +using WTF::TextPosition0; +using WTF::TextPosition1; + +#endif // TextPosition_h diff --git a/JavaScriptCore/wtf/text/WTFString.cpp b/JavaScriptCore/wtf/text/WTFString.cpp index 5161477..6bb74f6 100644 --- a/JavaScriptCore/wtf/text/WTFString.cpp +++ b/JavaScriptCore/wtf/text/WTFString.cpp @@ -1,6 +1,6 @@ /* * (C) 1999 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. * Copyright (C) 2007-2009 Torch Mobile, Inc. * * This library is free software; you can redistribute it and/or @@ -22,7 +22,6 @@ #include "config.h" #include "WTFString.h" -#include <limits> #include <stdarg.h> #include <wtf/ASCIICType.h> #include <wtf/text/CString.h> @@ -32,9 +31,12 @@ #include <wtf/unicode/UTF8.h> #include <wtf/unicode/Unicode.h> +using namespace std; + namespace WTF { using namespace Unicode; +using namespace std; // Construct a string with UTF-16 data. String::String(const UChar* characters, unsigned length) @@ -52,7 +54,7 @@ String::String(const UChar* str) while (str[len] != UChar(0)) len++; - if (len > std::numeric_limits<unsigned>::max()) + if (len > numeric_limits<unsigned>::max()) CRASH(); m_impl = StringImpl::create(str, len); @@ -82,8 +84,9 @@ void String::append(const String& str) if (str.m_impl) { if (m_impl) { UChar* data; - RefPtr<StringImpl> newImpl = - StringImpl::createUninitialized(m_impl->length() + str.length(), data); + if (str.length() > numeric_limits<unsigned>::max() - m_impl->length()) + CRASH(); + RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(m_impl->length() + str.length(), data); memcpy(data, m_impl->characters(), m_impl->length() * sizeof(UChar)); memcpy(data + m_impl->length(), str.characters(), str.length() * sizeof(UChar)); m_impl = newImpl.release(); @@ -100,8 +103,9 @@ void String::append(char c) // call to fastMalloc every single time. if (m_impl) { UChar* data; - RefPtr<StringImpl> newImpl = - StringImpl::createUninitialized(m_impl->length() + 1, data); + if (m_impl->length() >= numeric_limits<unsigned>::max()) + CRASH(); + RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(m_impl->length() + 1, data); memcpy(data, m_impl->characters(), m_impl->length() * sizeof(UChar)); data[m_impl->length()] = c; m_impl = newImpl.release(); @@ -117,8 +121,9 @@ void String::append(UChar c) // call to fastMalloc every single time. if (m_impl) { UChar* data; - RefPtr<StringImpl> newImpl = - StringImpl::createUninitialized(m_impl->length() + 1, data); + if (m_impl->length() >= numeric_limits<unsigned>::max()) + CRASH(); + RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(m_impl->length() + 1, data); memcpy(data, m_impl->characters(), m_impl->length() * sizeof(UChar)); data[m_impl->length()] = c; m_impl = newImpl.release(); @@ -178,10 +183,9 @@ void String::append(const UChar* charactersToAppend, unsigned lengthToAppend) ASSERT(charactersToAppend); UChar* data; - if (lengthToAppend > std::numeric_limits<unsigned>::max() - length()) + if (lengthToAppend > numeric_limits<unsigned>::max() - length()) CRASH(); - RefPtr<StringImpl> newImpl = - StringImpl::createUninitialized(length() + lengthToAppend, data); + RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(length() + lengthToAppend, data); memcpy(data, characters(), length() * sizeof(UChar)); memcpy(data + length(), charactersToAppend, lengthToAppend * sizeof(UChar)); m_impl = newImpl.release(); @@ -201,10 +205,9 @@ void String::insert(const UChar* charactersToInsert, unsigned lengthToInsert, un ASSERT(charactersToInsert); UChar* data; - if (lengthToInsert > std::numeric_limits<unsigned>::max() - length()) + if (lengthToInsert > numeric_limits<unsigned>::max() - length()) CRASH(); - RefPtr<StringImpl> newImpl = - StringImpl::createUninitialized(length() + lengthToInsert, data); + RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(length() + lengthToInsert, data); memcpy(data, characters(), position * sizeof(UChar)); memcpy(data + position, charactersToInsert, lengthToInsert * sizeof(UChar)); memcpy(data + position + lengthToInsert, characters() + position, (length() - position) * sizeof(UChar)); @@ -237,8 +240,7 @@ void String::remove(unsigned position, int lengthToRemove) if (static_cast<unsigned>(lengthToRemove) > length() - position) lengthToRemove = length() - position; UChar* data; - RefPtr<StringImpl> newImpl = - StringImpl::createUninitialized(length() - lengthToRemove, data); + RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(length() - lengthToRemove, data); memcpy(data, characters(), position * sizeof(UChar)); memcpy(data + position, characters() + position + lengthToRemove, (length() - lengthToRemove - position) * sizeof(UChar)); @@ -695,6 +697,8 @@ CString String::utf8(bool strict) const // * We could allocate a CStringBuffer with an appropriate size to // have a good chance of being able to write the string into the // buffer without reallocing (say, 1.5 x length). + if (length > numeric_limits<unsigned>::max() / 3) + return CString(); Vector<char, 1024> bufferVector(length * 3); char* buffer = bufferVector.data(); @@ -725,7 +729,7 @@ CString String::utf8(bool strict) const String String::fromUTF8(const char* stringStart, size_t length) { - if (length > std::numeric_limits<unsigned>::max()) + if (length > numeric_limits<unsigned>::max()) CRASH(); if (!stringStart) @@ -787,8 +791,8 @@ static bool isCharacterAllowedInBase(UChar c, int base) template <typename IntegralType> static inline IntegralType toIntegralType(const UChar* data, size_t length, bool* ok, int base) { - static const IntegralType integralMax = std::numeric_limits<IntegralType>::max(); - static const bool isSigned = std::numeric_limits<IntegralType>::is_signed; + static const IntegralType integralMax = numeric_limits<IntegralType>::max(); + static const bool isSigned = numeric_limits<IntegralType>::is_signed; const IntegralType maxMultiplier = integralMax / base; IntegralType value = 0; diff --git a/JavaScriptCore/wtf/wtf.pri b/JavaScriptCore/wtf/wtf.pri index 83e71d8..1780334 100644 --- a/JavaScriptCore/wtf/wtf.pri +++ b/JavaScriptCore/wtf/wtf.pri @@ -8,6 +8,8 @@ SOURCES += \ wtf/dtoa.cpp \ wtf/DecimalNumber.cpp \ wtf/FastMalloc.cpp \ + wtf/gobject/GOwnPtr.cpp \ + wtf/gobject/GRefPtr.cpp \ wtf/HashTable.cpp \ wtf/MD5.cpp \ wtf/MainThread.cpp \ @@ -31,6 +33,12 @@ SOURCES += \ wtf/unicode/icu/CollatorICU.cpp \ wtf/unicode/UTF8.cpp +contains(DEFINES, USE_GSTREAMER=1) { + DEFINES += ENABLE_GLIB_SUPPORT=1 + PKGCONFIG += glib-2.0 gio-2.0 + CONFIG += link_pkgconfig +} + !contains(DEFINES, USE_SYSTEM_MALLOC) { SOURCES += wtf/TCSystemAlloc.cpp } diff --git a/JavaScriptCore/yarr/RegexCompiler.cpp b/JavaScriptCore/yarr/RegexCompiler.cpp index 9f9e028..ccfc94e 100644 --- a/JavaScriptCore/yarr/RegexCompiler.cpp +++ b/JavaScriptCore/yarr/RegexCompiler.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -235,11 +236,117 @@ private: Vector<CharacterRange> m_rangesUnicode; }; +struct BeginCharHelper { + BeginCharHelper(Vector<BeginChar>* beginChars, bool isCaseInsensitive = false) + : m_beginChars(beginChars) + , m_isCaseInsensitive(isCaseInsensitive) + {} + + void addBeginChar(BeginChar beginChar, Vector<TermChain>* hotTerms, QuantifierType quantityType, unsigned quantityCount) + { + if (quantityType == QuantifierFixedCount && quantityCount > 1) { + // We duplicate the first found character if the quantity of the term is more than one. eg.: /a{3}/ + beginChar.value |= beginChar.value << 16; + beginChar.mask |= beginChar.mask << 16; + addCharacter(beginChar); + } else if (quantityType == QuantifierFixedCount && quantityCount == 1 && hotTerms->size()) + // In case of characters with fixed quantifier we should check the next character as well. + linkHotTerms(beginChar, hotTerms); + else + // In case of greedy matching the next character checking is unnecessary therefore we just store + // the first character. + addCharacter(beginChar); + } + + // Merge two following BeginChars in the vector to reduce the number of character checks. + void merge(unsigned size) + { + for (unsigned i = 0; i < size; i++) { + BeginChar* curr = &m_beginChars->at(i); + BeginChar* next = &m_beginChars->at(i + 1); + + // If the current and the next size of value is different we should skip the merge process + // because the 16bit and 32bit values are unmergable. + if (curr->value <= 0xFFFF && next->value > 0xFFFF) + continue; + + unsigned diff = curr->value ^ next->value; + + curr->mask |= diff; + curr->value |= curr->mask; + + m_beginChars->remove(i + 1); + size--; + } + } + +private: + void addCharacter(BeginChar beginChar) + { + unsigned pos = 0; + unsigned range = m_beginChars->size(); + + // binary chop, find position to insert char. + while (range) { + unsigned index = range >> 1; + + int val = m_beginChars->at(pos+index).value - beginChar.value; + if (!val) + return; + if (val < 0) + range = index; + else { + pos += (index+1); + range -= (index+1); + } + } + + if (pos == m_beginChars->size()) + m_beginChars->append(beginChar); + else + m_beginChars->insert(pos, beginChar); + } + + // Create BeginChar objects by appending each terms from a hotTerms vector to an existing BeginChar object. + void linkHotTerms(BeginChar beginChar, Vector<TermChain>* hotTerms) + { + for (unsigned i = 0; i < hotTerms->size(); i++) { + PatternTerm hotTerm = hotTerms->at(i).term; + ASSERT(hotTerm.type == PatternTerm::TypePatternCharacter); + + UChar characterNext = hotTerm.patternCharacter; + + // Append a character to an existing BeginChar object. + if (characterNext <= 0x7f) { + unsigned mask = 0; + + if (m_isCaseInsensitive && isASCIIAlpha(characterNext)) { + mask = 32; + characterNext = toASCIILower(characterNext); + } + + addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask | (mask << 16))); + } else { + UChar upper, lower; + if (m_isCaseInsensitive && ((upper = Unicode::toUpper(characterNext)) != (lower = Unicode::toLower(characterNext)))) { + addCharacter(BeginChar(beginChar.value | (upper << 16), beginChar.mask)); + addCharacter(BeginChar(beginChar.value | (lower << 16), beginChar.mask)); + } else + addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask)); + } + } + } + + Vector<BeginChar>* m_beginChars; + bool m_isCaseInsensitive; +}; + class RegexPatternConstructor { public: RegexPatternConstructor(RegexPattern& pattern) : m_pattern(pattern) , m_characterClassConstructor(pattern.m_ignoreCase) + , m_beginCharHelper(&pattern.m_beginChars, pattern.m_ignoreCase) , m_invertParentheticalAssertion(false) { } @@ -649,12 +756,153 @@ public: loopDisjunction->m_alternatives.clear(); } } - - + + bool addBeginTerm(PatternTerm term, Vector<TermChain>* beginTerms, PatternAlternative* alternative, unsigned numTerms, unsigned termIndex, unsigned depth) + { + if (term.quantityType == QuantifierFixedCount) { + beginTerms->append(TermChain(term)); + if (depth < 2 && termIndex < numTerms - 1 && term.quantityCount == 1) + setupAlternativeBeginTerms(alternative, &beginTerms->last().hotTerms, termIndex + 1, depth + 1); + } else if (termIndex != numTerms - 1) { + beginTerms->append(TermChain(term)); + return true; + } + + return false; + } + + // This function collects the terms which are potentially matching the first number of depth characters in the result. + // If this function returns false then it found at least one term which makes the beginning character + // look-up optimization inefficient. + bool setupDisjunctionBeginTerms(PatternDisjunction* disjunction, Vector<TermChain>* beginTerms, unsigned depth) + { + for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { + PatternAlternative* alternative = disjunction->m_alternatives[alt]; + + if (!setupAlternativeBeginTerms(alternative, beginTerms, 0, depth)) + return false; + } + + return true; + } + + bool setupAlternativeBeginTerms(PatternAlternative* alternative, Vector<TermChain>* beginTerms, unsigned termIndex, unsigned depth) + { + bool checkNext = true; + unsigned numTerms = alternative->m_terms.size(); + + while (checkNext && termIndex < numTerms) { + PatternTerm term = alternative->m_terms[termIndex]; + checkNext = false; + + switch (term.type) { + case PatternTerm::TypeAssertionBOL: + case PatternTerm::TypeAssertionEOL: + case PatternTerm::TypeAssertionWordBoundary: + return false; + + case PatternTerm::TypeBackReference: + case PatternTerm::TypeForwardReference: + return false; + + case PatternTerm::TypePatternCharacter: + if (addBeginTerm(term, beginTerms, alternative, numTerms, termIndex, depth)) { + termIndex++; + checkNext = true; + } + break; + + case PatternTerm::TypeCharacterClass: + return false; + + case PatternTerm::TypeParentheticalAssertion: + if (term.invertOrCapture) + return false; + + case PatternTerm::TypeParenthesesSubpattern: + if (term.quantityType != QuantifierFixedCount) { + if (termIndex == numTerms - 1) + break; + + termIndex++; + checkNext = true; + + } + + if (!setupDisjunctionBeginTerms(term.parentheses.disjunction, beginTerms, depth)) + return false; + + break; + } + } + + return true; + } + + void setupBeginChars() + { + Vector<TermChain> beginTerms; + bool containsFixedCharacter = false; + + if ((!m_pattern.m_body->m_hasFixedSize || m_pattern.m_body->m_alternatives.size() > 1) + && setupDisjunctionBeginTerms(m_pattern.m_body, &beginTerms, 0)) { + unsigned size = beginTerms.size(); + + // If we haven't collected any terms we should abort the preparation of beginning character look-up optimization. + if (!size) + return; + + m_pattern.m_containsBeginChars = true; + + for (unsigned i = 0; i < size; i++) { + PatternTerm term = beginTerms[i].term; + + // We have just collected PatternCharacter terms, other terms are not allowed. + ASSERT(term.type == PatternTerm::TypePatternCharacter); + + if (term.quantityType == QuantifierFixedCount) + containsFixedCharacter = true; + + UChar character = term.patternCharacter; + unsigned mask = 0; + + if (character <= 0x7f) { + if (m_pattern.m_ignoreCase && isASCIIAlpha(character)) { + mask = 32; + character = toASCIILower(character); + } + + m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); + } else { + UChar upper, lower; + if (m_pattern.m_ignoreCase && ((upper = Unicode::toUpper(character)) != (lower = Unicode::toLower(character)))) { + m_beginCharHelper.addBeginChar(BeginChar(upper, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); + m_beginCharHelper.addBeginChar(BeginChar(lower, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); + } else + m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); + } + } + + // If the pattern doesn't contain terms with fixed quantifiers then the beginning character look-up optimization is inefficient. + if (!containsFixedCharacter) { + m_pattern.m_containsBeginChars = false; + return; + } + + size = m_pattern.m_beginChars.size(); + + if (size > 2) + m_beginCharHelper.merge(size - 1); + else if (size <= 1) + m_pattern.m_containsBeginChars = false; + } + } + private: RegexPattern& m_pattern; PatternAlternative* m_alternative; CharacterClassConstructor m_characterClassConstructor; + BeginCharHelper m_beginCharHelper; bool m_invertCharacterClass; bool m_invertParentheticalAssertion; }; @@ -687,6 +935,7 @@ const char* compileRegex(const UString& patternString, RegexPattern& pattern) constructor.optimizeBOL(); constructor.setupOffsets(); + constructor.setupBeginChars(); return 0; }; diff --git a/JavaScriptCore/yarr/RegexInterpreter.cpp b/JavaScriptCore/yarr/RegexInterpreter.cpp index ec96636..dc3024a 100644 --- a/JavaScriptCore/yarr/RegexInterpreter.cpp +++ b/JavaScriptCore/yarr/RegexInterpreter.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -195,6 +196,12 @@ public: return -1; } + int readPair() + { + ASSERT(pos + 1 < length); + return input[pos] | input[pos + 1] << 16; + } + int readChecked(int position) { ASSERT(position < 0); @@ -262,6 +269,11 @@ public: return (pos + position) == length; } + bool isNotAvailableInput(int position) + { + return (pos + position) > length; + } + private: const UChar* input; unsigned pos; @@ -591,20 +603,24 @@ public: unsigned count = term.atom.parenthesesDisjunction->m_numSubpatterns; context->restoreOutput(output, firstSubpatternId, count); } - bool parenthesesDoBacktrack(ByteTerm& term, BackTrackInfoParentheses* backTrack) + JSRegExpResult parenthesesDoBacktrack(ByteTerm& term, BackTrackInfoParentheses* backTrack) { while (backTrack->matchAmount) { ParenthesesDisjunctionContext* context = backTrack->lastContext; - if (matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true)) - return true; + JSRegExpResult result = matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true); + if (result == JSRegExpMatch) + return JSRegExpMatch; resetMatches(term, context); popParenthesesDisjunctionContext(backTrack); freeParenthesesDisjunctionContext(context); + + if (result != JSRegExpNoMatch) + return result; } - return false; + return JSRegExpNoMatch; } bool matchParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context) @@ -765,7 +781,7 @@ public: return false; } - bool matchParentheses(ByteTerm& term, DisjunctionContext* context) + JSRegExpResult matchParentheses(ByteTerm& term, DisjunctionContext* context) { ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern); @@ -786,31 +802,42 @@ public: while (backTrack->matchAmount < term.atom.quantityCount) { // Try to do a match, and it it succeeds, add it to the list. ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); - if (matchDisjunction(disjunctionBody, context->getDisjunctionContext(term))) + JSRegExpResult result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term)); + if (result == JSRegExpMatch) appendParenthesesDisjunctionContext(backTrack, context); else { // The match failed; try to find an alternate point to carry on from. resetMatches(term, context); freeParenthesesDisjunctionContext(context); - if (!parenthesesDoBacktrack(term, backTrack)) - return false; + + if (result == JSRegExpNoMatch) { + JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack); + if (backtrackResult != JSRegExpMatch) + return backtrackResult; + } else + return result; } } ASSERT(backTrack->matchAmount == term.atom.quantityCount); ParenthesesDisjunctionContext* context = backTrack->lastContext; recordParenthesesMatch(term, context); - return true; + return JSRegExpMatch; } case QuantifierGreedy: { while (backTrack->matchAmount < term.atom.quantityCount) { ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); - if (matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term))) + JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term)); + if (result == JSRegExpMatch) appendParenthesesDisjunctionContext(backTrack, context); else { resetMatches(term, context); freeParenthesesDisjunctionContext(context); + + if (result != JSRegExpNoMatch) + return result; + break; } } @@ -819,15 +846,15 @@ public: ParenthesesDisjunctionContext* context = backTrack->lastContext; recordParenthesesMatch(term, context); } - return true; + return JSRegExpMatch; } case QuantifierNonGreedy: - return true; + return JSRegExpMatch; } ASSERT_NOT_REACHED(); - return false; + return JSRegExpErrorNoMatch; } // Rules for backtracking differ depending on whether this is greedy or non-greedy. @@ -840,7 +867,7 @@ public: // Non-greedy, we've already done the one less case, so don't match on popping. // We haven't done the one more case, so always try to add that. // - bool backtrackParentheses(ByteTerm& term, DisjunctionContext* context) + JSRegExpResult backtrackParentheses(ByteTerm& term, DisjunctionContext* context) { ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern); @@ -859,44 +886,58 @@ public: ASSERT(backTrack->matchAmount == term.atom.quantityCount); ParenthesesDisjunctionContext* context = 0; + JSRegExpResult result = parenthesesDoBacktrack(term, backTrack); - if (!parenthesesDoBacktrack(term, backTrack)) - return false; + if (result != JSRegExpMatch) + return result; // While we haven't yet reached our fixed limit, while (backTrack->matchAmount < term.atom.quantityCount) { // Try to do a match, and it it succeeds, add it to the list. context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); - if (matchDisjunction(disjunctionBody, context->getDisjunctionContext(term))) + result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term)); + + if (result == JSRegExpMatch) appendParenthesesDisjunctionContext(backTrack, context); else { // The match failed; try to find an alternate point to carry on from. resetMatches(term, context); freeParenthesesDisjunctionContext(context); - if (!parenthesesDoBacktrack(term, backTrack)) - return false; + + if (result == JSRegExpNoMatch) { + JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack); + if (backtrackResult != JSRegExpMatch) + return backtrackResult; + } else + return result; } } ASSERT(backTrack->matchAmount == term.atom.quantityCount); context = backTrack->lastContext; recordParenthesesMatch(term, context); - return true; + return JSRegExpMatch; } case QuantifierGreedy: { if (!backTrack->matchAmount) - return false; + return JSRegExpNoMatch; ParenthesesDisjunctionContext* context = backTrack->lastContext; - if (matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true)) { + JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true); + if (result == JSRegExpMatch) { while (backTrack->matchAmount < term.atom.quantityCount) { ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); - if (matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term))) + JSRegExpResult parenthesesResult = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term)); + if (parenthesesResult == JSRegExpMatch) appendParenthesesDisjunctionContext(backTrack, context); else { resetMatches(term, context); freeParenthesesDisjunctionContext(context); + + if (parenthesesResult != JSRegExpNoMatch) + return parenthesesResult; + break; } } @@ -904,63 +945,108 @@ public: resetMatches(term, context); popParenthesesDisjunctionContext(backTrack); freeParenthesesDisjunctionContext(context); + + if (result != JSRegExpNoMatch) + return result; } if (backTrack->matchAmount) { ParenthesesDisjunctionContext* context = backTrack->lastContext; recordParenthesesMatch(term, context); } - return true; + return JSRegExpMatch; } case QuantifierNonGreedy: { // If we've not reached the limit, try to add one more match. if (backTrack->matchAmount < term.atom.quantityCount) { ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); - if (matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term))) { + JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term)); + if (result == JSRegExpMatch) { appendParenthesesDisjunctionContext(backTrack, context); recordParenthesesMatch(term, context); - return true; - } else { - resetMatches(term, context); - freeParenthesesDisjunctionContext(context); + return JSRegExpMatch; } + + resetMatches(term, context); + freeParenthesesDisjunctionContext(context); + + if (result != JSRegExpNoMatch) + return result; } // Nope - okay backtrack looking for an alternative. while (backTrack->matchAmount) { ParenthesesDisjunctionContext* context = backTrack->lastContext; - if (matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true)) { + JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true); + if (result == JSRegExpMatch) { // successful backtrack! we're back in the game! if (backTrack->matchAmount) { context = backTrack->lastContext; recordParenthesesMatch(term, context); } - return true; + return JSRegExpMatch; } // pop a match off the stack resetMatches(term, context); popParenthesesDisjunctionContext(backTrack); freeParenthesesDisjunctionContext(context); + + return result; } - return false; + return JSRegExpNoMatch; } } ASSERT_NOT_REACHED(); - return false; + return JSRegExpErrorNoMatch; + } + + void lookupForBeginChars() + { + int character; + bool firstSingleCharFound; + + while (true) { + if (input.isNotAvailableInput(2)) + return; + + firstSingleCharFound = false; + + character = input.readPair(); + + for (unsigned i = 0; i < pattern->m_beginChars.size(); ++i) { + BeginChar bc = pattern->m_beginChars[i]; + + if (!firstSingleCharFound && bc.value <= 0xFFFF) { + firstSingleCharFound = true; + character &= 0xFFFF; + } + + if ((character | bc.mask) == bc.value) + return; + } + + input.next(); + } } #define MATCH_NEXT() { ++context->term; goto matchAgain; } #define BACKTRACK() { --context->term; goto backtrack; } #define currentTerm() (disjunction->terms[context->term]) - bool matchDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false) + JSRegExpResult matchDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false, bool isBody = false) { + if (!--remainingMatchCount) + return JSRegExpErrorHitLimit; + if (btrack) BACKTRACK(); + if (pattern->m_containsBeginChars && isBody) + lookupForBeginChars(); + context->matchBegin = input.getPos(); context->term = 0; @@ -972,14 +1058,14 @@ public: MATCH_NEXT(); case ByteTerm::TypeSubpatternEnd: context->matchEnd = input.getPos(); - return true; + return JSRegExpMatch; case ByteTerm::TypeBodyAlternativeBegin: MATCH_NEXT(); case ByteTerm::TypeBodyAlternativeDisjunction: case ByteTerm::TypeBodyAlternativeEnd: context->matchEnd = input.getPos(); - return true; + return JSRegExpMatch; case ByteTerm::TypeAlternativeBegin: MATCH_NEXT(); @@ -1069,10 +1155,16 @@ public: if (matchBackReference(currentTerm(), context)) MATCH_NEXT(); BACKTRACK(); - case ByteTerm::TypeParenthesesSubpattern: - if (matchParentheses(currentTerm(), context)) + case ByteTerm::TypeParenthesesSubpattern: { + JSRegExpResult result = matchParentheses(currentTerm(), context); + + if (result == JSRegExpMatch) { MATCH_NEXT(); + } else if (result != JSRegExpNoMatch) + return result; + BACKTRACK(); + } case ByteTerm::TypeParenthesesSubpatternOnceBegin: if (matchParenthesesOnceBegin(currentTerm(), context)) MATCH_NEXT(); @@ -1104,7 +1196,7 @@ public: switch (currentTerm().type) { case ByteTerm::TypeSubpatternBegin: - return false; + return JSRegExpNoMatch; case ByteTerm::TypeSubpatternEnd: ASSERT_NOT_REACHED(); @@ -1116,9 +1208,13 @@ public: MATCH_NEXT(); if (input.atEnd()) - return false; + return JSRegExpNoMatch; input.next(); + + if (pattern->m_containsBeginChars && isBody) + lookupForBeginChars(); + context->matchBegin = input.getPos(); if (currentTerm().alternative.onceThrough) @@ -1172,10 +1268,16 @@ public: if (backtrackBackReference(currentTerm(), context)) MATCH_NEXT(); BACKTRACK(); - case ByteTerm::TypeParenthesesSubpattern: - if (backtrackParentheses(currentTerm(), context)) + case ByteTerm::TypeParenthesesSubpattern: { + JSRegExpResult result = backtrackParentheses(currentTerm(), context); + + if (result == JSRegExpMatch) { MATCH_NEXT(); + } else if (result != JSRegExpNoMatch) + return result; + BACKTRACK(); + } case ByteTerm::TypeParenthesesSubpatternOnceBegin: if (backtrackParenthesesOnceBegin(currentTerm(), context)) MATCH_NEXT(); @@ -1199,20 +1301,23 @@ public: } ASSERT_NOT_REACHED(); - return false; + return JSRegExpErrorNoMatch; } - bool matchNonZeroDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false) + JSRegExpResult matchNonZeroDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false) { - if (matchDisjunction(disjunction, context, btrack)) { + JSRegExpResult result = matchDisjunction(disjunction, context, btrack); + + if (result == JSRegExpMatch) { while (context->matchBegin == context->matchEnd) { - if (!matchDisjunction(disjunction, context, true)) - return false; + result = matchDisjunction(disjunction, context, true); + if (result != JSRegExpMatch) + return result; } - return true; + return JSRegExpMatch; } - return false; + return result; } int interpret() @@ -1226,7 +1331,8 @@ public: DisjunctionContext* context = allocDisjunctionContext(pattern->m_body.get()); - if (matchDisjunction(pattern->m_body.get(), context)) { + JSRegExpResult result = matchDisjunction(pattern->m_body.get(), context, false, true); + if (result == JSRegExpMatch) { output[0] = context->matchBegin; output[1] = context->matchEnd; } @@ -1235,6 +1341,9 @@ public: pattern->m_allocator->stopAllocator(); + if (output[0] == -1 && result != JSRegExpNoMatch) + return result; + return output[0]; } @@ -1243,6 +1352,7 @@ public: , output(output) , input(inputChar, start, length) , allocatorPool(0) + , remainingMatchCount(matchLimit) { } @@ -1251,6 +1361,7 @@ private: int* output; InputStream input; BumpPointerPool* allocatorPool; + unsigned remainingMatchCount; }; diff --git a/JavaScriptCore/yarr/RegexInterpreter.h b/JavaScriptCore/yarr/RegexInterpreter.h index 37f17fe..dae8f9d 100644 --- a/JavaScriptCore/yarr/RegexInterpreter.h +++ b/JavaScriptCore/yarr/RegexInterpreter.h @@ -40,6 +40,21 @@ using WTF::BumpPointerAllocator; namespace JSC { namespace Yarr { +// TODO move the matchLimit constant and the JSRegExpResult enum to the JSRegExp.h when pcre is removed. + +// The below limit restricts the number of "recursive" match calls in order to +// avoid spending exponential time on complex regular expressions. +static const unsigned matchLimit = 1000000; + +enum JSRegExpResult { + JSRegExpMatch = 1, + JSRegExpNoMatch = 0, + JSRegExpErrorNoMatch = -1, + JSRegExpErrorHitLimit = -2, + JSRegExpErrorNoMemory = -3, + JSRegExpErrorInternal = -4 +}; + class ByteDisjunction; struct ByteTerm { @@ -309,6 +324,7 @@ struct BytecodePattern : FastAllocBase { : m_body(body) , m_ignoreCase(pattern.m_ignoreCase) , m_multiline(pattern.m_multiline) + , m_containsBeginChars(pattern.m_containsBeginChars) , m_allocator(allocator) { newlineCharacterClass = pattern.newlineCharacterClass(); @@ -320,6 +336,8 @@ struct BytecodePattern : FastAllocBase { // array, so that it won't delete them on destruction. We'll // take responsibility for that. pattern.m_userCharacterClasses.clear(); + + m_beginChars.append(pattern.m_beginChars); } ~BytecodePattern() @@ -331,12 +349,16 @@ struct BytecodePattern : FastAllocBase { OwnPtr<ByteDisjunction> m_body; bool m_ignoreCase; bool m_multiline; + bool m_containsBeginChars; // Each BytecodePattern is associated with a RegExp, each RegExp is associated // with a JSGlobalData. Cache a pointer to out JSGlobalData's m_regexAllocator. BumpPointerAllocator* m_allocator; CharacterClass* newlineCharacterClass; CharacterClass* wordcharCharacterClass; + + Vector<BeginChar> m_beginChars; + private: Vector<ByteDisjunction*> m_allParenthesesInfo; Vector<CharacterClass*> m_userCharacterClasses; diff --git a/JavaScriptCore/yarr/RegexJIT.h b/JavaScriptCore/yarr/RegexJIT.h index 5d587b2..02e905d 100644 --- a/JavaScriptCore/yarr/RegexJIT.h +++ b/JavaScriptCore/yarr/RegexJIT.h @@ -30,9 +30,9 @@ #include "MacroAssembler.h" #include "RegexPattern.h" -#include <UString.h> +#include "UString.h" -#include <pcre.h> +#include "pcre.h" struct JSRegExp; // temporary, remove when fallback is removed. #if CPU(X86) && !COMPILER(MSVC) diff --git a/JavaScriptCore/yarr/RegexParser.h b/JavaScriptCore/yarr/RegexParser.h index 8a5eeba..ede9417 100644 --- a/JavaScriptCore/yarr/RegexParser.h +++ b/JavaScriptCore/yarr/RegexParser.h @@ -28,7 +28,7 @@ #if ENABLE(YARR) -#include <UString.h> +#include "UString.h" #include <limits.h> #include <wtf/ASCIICType.h> #include <wtf/unicode/Unicode.h> diff --git a/JavaScriptCore/yarr/RegexPattern.h b/JavaScriptCore/yarr/RegexPattern.h index eecbd43..be31fcd 100644 --- a/JavaScriptCore/yarr/RegexPattern.h +++ b/JavaScriptCore/yarr/RegexPattern.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -283,11 +284,36 @@ CharacterClass* nondigitsCreate(); CharacterClass* nonspacesCreate(); CharacterClass* nonwordcharCreate(); +struct TermChain { + TermChain(PatternTerm term) + : term(term) + {} + + PatternTerm term; + Vector<TermChain> hotTerms; +}; + +struct BeginChar { + BeginChar() + : value(0) + , mask(0) + {} + + BeginChar(unsigned value, unsigned mask) + : value(value) + , mask(mask) + {} + + unsigned value; + unsigned mask; +}; + struct RegexPattern { RegexPattern(bool ignoreCase, bool multiline) : m_ignoreCase(ignoreCase) , m_multiline(multiline) , m_containsBackreferences(false) + , m_containsBeginChars(false) , m_containsBOL(false) , m_numSubpatterns(0) , m_maxBackReference(0) @@ -313,6 +339,7 @@ struct RegexPattern { m_maxBackReference = 0; m_containsBackreferences = false; + m_containsBeginChars = false; m_containsBOL = false; newlineCached = 0; @@ -327,6 +354,7 @@ struct RegexPattern { m_disjunctions.clear(); deleteAllValues(m_userCharacterClasses); m_userCharacterClasses.clear(); + m_beginChars.clear(); } bool containsIllegalBackReference() @@ -380,12 +408,14 @@ struct RegexPattern { bool m_ignoreCase : 1; bool m_multiline : 1; bool m_containsBackreferences : 1; + bool m_containsBeginChars : 1; bool m_containsBOL : 1; unsigned m_numSubpatterns; unsigned m_maxBackReference; PatternDisjunction* m_body; Vector<PatternDisjunction*, 4> m_disjunctions; Vector<CharacterClass*> m_userCharacterClasses; + Vector<BeginChar> m_beginChars; private: CharacterClass* newlineCached; |