diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
commit | cd44dc59cdfc39534aef4d417e9f3c412e3be139 (patch) | |
tree | 8d89889ba95ed6ec9322e733846cc9cce9d7dff1 /Source/JavaScriptCore | |
parent | d11f84f5b5cdc0d92a08af01b13472fdd5f9acb9 (diff) | |
download | qtwebkit-cd44dc59cdfc39534aef4d417e9f3c412e3be139.tar.gz |
Imported WebKit commit fce473cb4d55aa9fe9d0b0322a2fffecb731b961 (http://svn.webkit.org/repository/webkit/trunk@106560)
Diffstat (limited to 'Source/JavaScriptCore')
309 files changed, 11605 insertions, 4375 deletions
diff --git a/Source/JavaScriptCore/API/JSObjectRef.cpp b/Source/JavaScriptCore/API/JSObjectRef.cpp index 99b41b685..cd8d7159e 100644 --- a/Source/JavaScriptCore/API/JSObjectRef.cpp +++ b/Source/JavaScriptCore/API/JSObjectRef.cpp @@ -274,7 +274,7 @@ void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope JSValue jsValue = toJS(exec, value); if (attributes && !jsObject->hasProperty(exec, name)) - jsObject->methodTable()->putWithAttributes(jsObject, exec, name, jsValue, attributes); + jsObject->methodTable()->putDirectVirtual(jsObject, exec, name, jsValue, attributes); else { PutPropertySlot slot; jsObject->methodTable()->put(jsObject, exec, name, jsValue, slot); diff --git a/Source/JavaScriptCore/API/JSValueRef.cpp b/Source/JavaScriptCore/API/JSValueRef.cpp index c89e267a4..1b4e03bde 100644 --- a/Source/JavaScriptCore/API/JSValueRef.cpp +++ b/Source/JavaScriptCore/API/JSValueRef.cpp @@ -293,7 +293,7 @@ JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* JSValue jsValue = toJS(exec, value); - RefPtr<OpaqueJSString> stringRef(OpaqueJSString::create(jsValue.toString(exec))); + RefPtr<OpaqueJSString> stringRef(OpaqueJSString::create(jsValue.toString(exec)->value(exec))); if (exec->hadException()) { if (exception) *exception = toRef(exec, exec->exception()); diff --git a/Source/JavaScriptCore/API/OpaqueJSString.h b/Source/JavaScriptCore/API/OpaqueJSString.h index 5c24f7510..1c63150cf 100644 --- a/Source/JavaScriptCore/API/OpaqueJSString.h +++ b/Source/JavaScriptCore/API/OpaqueJSString.h @@ -46,7 +46,7 @@ struct OpaqueJSString : public ThreadSafeRefCounted<OpaqueJSString> { return adoptRef(new OpaqueJSString(characters, length)); } - static PassRefPtr<OpaqueJSString> create(const JSC::UString&); + JS_EXPORT_PRIVATE static PassRefPtr<OpaqueJSString> create(const JSC::UString&); UChar* characters() { return this ? m_characters : 0; } unsigned length() { return this ? m_length : 0; } diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index 00e0296c0..a620c5a52 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -14,6 +14,7 @@ SET(JavaScriptCore_INCLUDE_DIRECTORIES "${JAVASCRIPTCORE_DIR}/parser" "${JAVASCRIPTCORE_DIR}/profiler" "${JAVASCRIPTCORE_DIR}/runtime" + "${JAVASCRIPTCORE_DIR}/tools" "${JAVASCRIPTCORE_DIR}/yarr" "${JAVASCRIPTCORE_DIR}/wtf" "${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}" @@ -35,12 +36,16 @@ SET(JavaScriptCore_SOURCES API/OpaqueJSString.cpp bytecode/CallLinkInfo.cpp + bytecode/CallLinkStatus.cpp bytecode/CodeBlock.cpp bytecode/DFGExitProfile.cpp + bytecode/GetByIdStatus.cpp bytecode/JumpTable.cpp bytecode/MethodCallLinkInfo.cpp + bytecode/MethodCallLinkStatus.cpp bytecode/Opcode.cpp bytecode/PredictedType.cpp + bytecode/PutByIdStatus.cpp bytecode/SamplingTool.cpp bytecode/StructureStubInfo.cpp bytecode/ValueProfile.cpp @@ -69,7 +74,7 @@ SET(JavaScriptCore_SOURCES dfg/DFGSpeculativeJIT64.cpp dfg/DFGThunks.cpp - heap/AllocationSpace.cpp + heap/BumpSpace.cpp heap/DFGCodeBlocks.cpp heap/Heap.cpp heap/HandleHeap.cpp @@ -84,6 +89,7 @@ SET(JavaScriptCore_SOURCES debugger/DebuggerActivation.cpp debugger/DebuggerCallFrame.cpp + interpreter/AbstractPC.cpp interpreter/CallFrame.cpp interpreter/Interpreter.cpp interpreter/RegisterFile.cpp @@ -195,6 +201,9 @@ SET(JavaScriptCore_SOURCES runtime/TimeoutChecker.cpp runtime/UString.cpp + tools/CodeProfile.cpp + tools/CodeProfiling.cpp + yarr/YarrPattern.cpp yarr/YarrInterpreter.cpp yarr/YarrJIT.cpp diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index c8b43b41c..1f53cd789 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,3311 @@ +2012-02-01 Michael Saboff <msaboff@apple.com> + + Yarr crash with regexp replace + https://bugs.webkit.org/show_bug.cgi?id=67454 + + Reviewed by Gavin Barraclough. + + Properly handle the case of a back reference to an unmatched + subpattern by always matching without consuming any characters. + + * yarr/YarrInterpreter.cpp: + (JSC::Yarr::Interpreter::matchBackReference): + (JSC::Yarr::Interpreter::backtrackBackReference): + +2012-02-01 Gavin Barraclough <barraclough@apple.com> + + calling function on catch block scope containing an eval result in wrong this value being passed + https://bugs.webkit.org/show_bug.cgi?id=77581 + + Reviewed by Oliver Hunt. + + javascript:function F(){ return 'F' in this; }; try { throw F; } catch (e) { eval(""); alert(e()); } + + * bytecompiler/NodesCodegen.cpp: + (JSC::TryNode::emitBytecode): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createTryStatement): + * parser/NodeConstructors.h: + (JSC::TryNode::TryNode): + * parser/Nodes.h: + (TryNode): + * parser/Parser.cpp: + (JSC::::parseTryStatement): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createTryStatement): + * runtime/JSObject.h: + (JSObject): + (JSC::JSObject::isStaticScopeObject): + (JSC): + +2012-02-01 Oliver Hunt <oliver@apple.com> + + Add support for inferred function names + https://bugs.webkit.org/show_bug.cgi?id=77579 + + Reviewed by Gavin Barraclough. + + Add new "inferred" names to function expressions, getters, and setters. + This property is not exposed to JS, so is only visible in the debugger + and profiler. + + * JavaScriptCore.exp: + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::makeFunction): + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::calculatedFunctionName): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createAssignResolve): + (JSC::ASTBuilder::createGetterOrSetterProperty): + (JSC::ASTBuilder::createProperty): + (JSC::ASTBuilder::makeAssignNode): + * parser/Nodes.h: + (JSC::FunctionBodyNode::setInferredName): + (JSC::FunctionBodyNode::inferredName): + (FunctionBodyNode): + * profiler/Profiler.cpp: + (JSC): + (JSC::Profiler::createCallIdentifier): + (JSC::createCallIdentifierFromFunctionImp): + * runtime/Executable.cpp: + (JSC::FunctionExecutable::FunctionExecutable): + (JSC::FunctionExecutable::fromGlobalCode): + * runtime/Executable.h: + (JSC::FunctionExecutable::create): + (JSC::FunctionExecutable::inferredName): + (FunctionExecutable): + * runtime/JSFunction.cpp: + (JSC::JSFunction::calculatedDisplayName): + (JSC): + (JSC::getCalculatedDisplayName): + * runtime/JSFunction.h: + (JSC): + +2012-02-01 Filip Pizlo <fpizlo@apple.com> + + DFG should fold double-to-int conversions + https://bugs.webkit.org/show_bug.cgi?id=77532 + + Reviewed by Oliver Hunt. + + Performance neutral on major benchmarks. But it makes calling V8's + Math.random() 4x faster. + + * bytecode/CodeBlock.cpp: + (JSC): + (JSC::CodeBlock::addOrFindConstant): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::addConstant): + (CodeBlock): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::toInt32): + (ByteCodeParser): + (JSC::DFG::ByteCodeParser::getJSConstantForValue): + (JSC::DFG::ByteCodeParser::isInt32Constant): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::addShouldSpeculateInteger): + (Graph): + (JSC::DFG::Graph::addImmediateShouldSpeculateInteger): + * dfg/DFGPropagator.cpp: + (JSC::DFG::Propagator::propagateNodePredictions): + (JSC::DFG::Propagator::doRoundOfDoubleVoting): + (JSC::DFG::Propagator::fixupNode): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileAdd): + (DFG): + (JSC::DFG::SpeculativeJIT::compileArithSub): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::valueOfNumberConstantAsInt32): + (SpeculativeJIT): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * runtime/JSValueInlineMethods.h: + (JSC::JSValue::asDouble): + +2012-02-01 Filip Pizlo <fpizlo@apple.com> + + DFG graph dump for GetScopedVar should show the correct prediction + https://bugs.webkit.org/show_bug.cgi?id=77530 + + Reviewed by Geoff Garen. + + GetScopedVar has a heap prediction, not a variable prediction. But it does + have a variable. Hence we need to check for heap predictions before checking + for variable predictions. + + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + +2012-02-01 Mark Hahnenberg <mhahnenberg@apple.com> + + Replace JSArray destructor with finalizer + https://bugs.webkit.org/show_bug.cgi?id=77488 + + Reviewed by Geoffrey Garen. + + * JavaScriptCore.exp: + * runtime/JSArray.cpp: + (JSC::JSArray::finalize): Added finalizer. + (JSC::JSArray::allocateSparseMap): Factored out code for allocating new sparse maps. + (JSC): + (JSC::JSArray::deallocateSparseMap): Factored out code for deallocating sparse maps. + (JSC::JSArray::enterDictionaryMode): Renamed enterSparseMode to enterDictionaryMode + because the old name was confusing because we could have a sparse array that never + called enterSparseMode. + (JSC::JSArray::defineOwnNumericProperty): + (JSC::JSArray::setLengthWritable): + (JSC::JSArray::putByIndexBeyondVectorLength): + (JSC::JSArray::setLength): + (JSC::JSArray::pop): + (JSC::JSArray::sort): + (JSC::JSArray::compactForSorting): + * runtime/JSArray.h: + (JSArray): + +2012-02-01 Andy Wingo <wingo@igalia.com> + + Refactor identifier resolution in BytecodeGenerator + https://bugs.webkit.org/show_bug.cgi?id=76285 + + Reviewed by Geoffrey Garen. + + * bytecompiler/BytecodeGenerator.h: + (JSC::ResolveResult): New class, to describe the storage + location corresponding to an identifier in a program. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::resolve): New function, replacing + findScopedProperty. + (JSC::BytecodeGenerator::resolveConstDecl): New function, + encapsulating what ConstDeclNode::emitBytecode used to do. + (JSC::BytecodeGenerator::emitGetStaticVar): + (JSC::BytecodeGenerator::emitPutStaticVar): New functions, + corresponding to the old emitGetScopedVar and emitPutScopedVar. + (JSC::BytecodeGenerator::registerFor): Remove version that took an + Identifier&; replaced by ResolveResult::local(). + (JSC::BytecodeGenerator::emitResolve): + (JSC::BytecodeGenerator::emitResolveBase): + (JSC::BytecodeGenerator::emitResolveBaseForPut): + (JSC::BytecodeGenerator::emitResolveWithBase): + (JSC::BytecodeGenerator::emitResolveWithThis): Change to accept a + "resolveResult" argument. This is more clear, and reduces the + amount of double analysis happening at compile-time. + * bytecompiler/NodesCodegen.cpp: + (JSC::ResolveNode::emitBytecode): + (JSC::EvalFunctionCallNode::emitBytecode): + (JSC::FunctionCallResolveNode::emitBytecode): + (JSC::PostfixResolveNode::emitBytecode): + (JSC::DeleteResolveNode::emitBytecode): + (JSC::TypeOfResolveNode::emitBytecode): + (JSC::PrefixResolveNode::emitBytecode): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + (JSC::ForInNode::emitBytecode): Refactor to use the new + ResolveResult structure. + +2012-02-01 Csaba Osztrogonác <ossy@webkit.org> + + Implement Error.stack + https://bugs.webkit.org/show_bug.cgi?id=66994 + + Unreviewed, rolling out r106407. + + * JavaScriptCore.exp: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * interpreter/AbstractPC.cpp: + (JSC::AbstractPC::AbstractPC): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::throwException): + * interpreter/Interpreter.h: + (JSC): + (Interpreter): + * jsc.cpp: + (GlobalObject::finishCreation): + * parser/Parser.h: + (JSC::::parse): + * runtime/CommonIdentifiers.h: + * runtime/Error.cpp: + (JSC::addErrorInfo): + * runtime/Error.h: + (JSC): + +2012-01-31 Hajime Morrita <morrita@chromium.org> + + Add missing JS_PRIVATE_EXPORTs + https://bugs.webkit.org/show_bug.cgi?id=77507 + + Reviewed by Kevin Ollivier. + + * heap/MarkedSpace.h: + (MarkedSpace): + * interpreter/Interpreter.h: + (Interpreter): + * runtime/JSValue.h: + (JSValue): + * wtf/text/AtomicString.h: + (WTF::AtomicString::add): + * wtf/text/WTFString.h: + (WTF): + +2012-01-31 Geoffrey Garen <ggaren@apple.com> + + Stop using -fomit-frame-pointer + https://bugs.webkit.org/show_bug.cgi?id=77403 + + Reviewed by Filip Pizlo. + + JavaScriptCore is too fast. I'm just the man to fix it. + + * Configurations/JavaScriptCore.xcconfig: + +2012-01-31 Michael Saboff <msaboff@apple.com> + + StringProtoFuncToUpperCase should call StringImpl::upper similar to StringProtoToLowerCase + https://bugs.webkit.org/show_bug.cgi?id=76647 + + Reviewed by Darin Adler. + + Changed stringProtoFuncToUpperCase to call StringImpl::upper() in a manor similar + to stringProtoFuncToLowerCase(). Fixed StringImpl::upper() to handle to special + cases. One case is s-sharp (0xdf) which converts to "SS". The other case is + for characters which become 16 bit values when converted to upper case. For + those, we up convert the the source string and use the 16 bit path. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncToUpperCase): + * wtf/text/StringImpl.cpp: + (WTF::StringImpl::upper): + * wtf/unicode/CharacterNames.h: + (smallLetterSharpS): New constant + +2012-01-31 Oliver Hunt <oliver@apple.com> + + Remove unneeded sourceId property + https://bugs.webkit.org/show_bug.cgi?id=77495 + + Reviewed by Filip Pizlo. + + sourceId isn't used anymore, so we'll just remove it. + + * runtime/Error.cpp: + (JSC): + (JSC::addErrorInfo): + (JSC::hasErrorInfo): + +2012-01-31 Oliver Hunt <oliver@apple.com> + + Implement Error.stack + https://bugs.webkit.org/show_bug.cgi?id=66994 + + Reviewed by Gavin Barraclough. + + Original patch by Juan Carlos Montemayor Elosua: + This patch utilizes topCallFrame to create a stack trace when + an error is thrown. Users will also be able to use the stack() + command in jsc to get arrays with stack trace information. + + Modified to be correct on ToT, with a variety of correctness, + performance, and security improvements. + + * JavaScriptCore.exp: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * interpreter/Interpreter.cpp: + (JSC::getCallerLine): + (JSC::getSourceURLFromCallFrame): + (JSC::getStackFrameCodeType): + (JSC::Interpreter::getStackTrace): + (JSC::Interpreter::throwException): + * interpreter/Interpreter.h: + (JSC::StackFrame::toString): + * jsc.cpp: + (GlobalObject::finishCreation): + (functionJSCStack): + * parser/Parser.h: + (JSC::Parser::parse): + * runtime/CommonIdentifiers.h: + * runtime/Error.cpp: + (JSC::addErrorInfo): + * runtime/Error.h: + +2012-01-31 Scott Graham <scottmg@chromium.org> + + [Chromium] Remove references to gyp cygwin build target + https://bugs.webkit.org/show_bug.cgi?id=77253 + + Reviewed by Julien Chaffraix. + + Target dependency is no longer required, it's done earlier in the + build process. + + * JavaScriptCore.gyp/JavaScriptCore.gyp: + +2012-01-31 Michael Saboff <msaboff@apple.com> + + ASSERT(m_jumpsToLink.isEmpty()) failing in ARMv7Assembler dtor + https://bugs.webkit.org/show_bug.cgi?id=77443 + + Reviewed by Gavin Barraclough. + + Removed failing ASSERT() and thus destructor. The ASSERT isn't needed. + We are hitting it in the YARR JIT case where we bail out and go to the + interpreter with a partially JIT'ed function. Since we haven't linked + the JIT'ed code, there is likely to be some unresolved jumps in the vector + when the ARMv7Assembler destructor is called. For the case where we + complete the JIT process, we clear the vector at the end of + LinkBuffer::linkCode (LinkBuffer.h:292). + + * assembler/ARMv7Assembler.h: + (ARMv7Assembler): + +2012-01-31 Anders Carlsson <andersca@apple.com> + + Vector<T>::operator== shouldn't require T to have operator!= + https://bugs.webkit.org/show_bug.cgi?id=77448 + + Reviewed by Andreas Kling. + + Change VectorComparer::compare to use !(a == b) instead of a != b since + it makes more sense for Vector::operator== to use the element's operator==. + + * wtf/Vector.h: + +2012-01-30 Oliver Hunt <oliver@apple.com> + + get_by_val_arguments is broken in the interpreter + https://bugs.webkit.org/show_bug.cgi?id=77389 + + Reviewed by Gavin Barraclough. + + When get_by_val had wad a value profile added, the same slot was not added to + get_by_val_arguments. This broke the interpreter as the interpreter falls + back on its regular get_by_val implementation. + + No tests are added as the interpreter is fairly broken in its + current state (multiple tests fail due to this bug). + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + (JSC): + (): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetArgumentByVal): + +2012-01-30 Oliver Hunt <oliver@apple.com> + + Unexpected syntax error + https://bugs.webkit.org/show_bug.cgi?id=77340 + + Reviewed by Gavin Barraclough. + + Function calls and new expressions have the same semantics for + assignment, so should simply share their lhs handling. + + * parser/Parser.cpp: + (JSC::::parseMemberExpression): + +2012-01-30 Gavin Barraclough <barraclough@apple.com> + + Unreviewed ARMv7 build fix. + + * tools/CodeProfiling.cpp: + (JSC): + (JSC::setProfileTimer): + (JSC::CodeProfiling::begin): + (JSC::CodeProfiling::end): + +2012-01-30 David Levin <levin@chromium.org> + + Using OS(WIN) or OS(MAC) should cause a build error. + https://bugs.webkit.org/show_bug.cgi?id=77162 + + Reviewed by Darin Adler. + + * wtf/Platform.h: Expand them into something that will + cause a compile error. + +2012-01-30 Yong Li <yoli@rim.com> + + [BlackBerry] OS(QNX) also has TM_GMTOFF, TM_ZONE, and TIMEGM + https://bugs.webkit.org/show_bug.cgi?id=77360 + + Reviewed by Rob Buis. + + Turn on HAVE(TM_GMTOFF), HAVE(TM_ZONE), and HAVE(TIMEGM) + for OS(QNX). + + * wtf/Platform.h: + +2012-01-30 Gavin Barraclough <barraclough@apple.com> + + Speculative Windows build fix. + + * assembler/MacroAssemblerCodeRef.h: + (FunctionPtr): + +2012-01-30 Gavin Barraclough <barraclough@apple.com> + + https://bugs.webkit.org/show_bug.cgi?id=77163 + MacroAssemblerCodeRef.h uses OS(WIN) instead of OS(WINDOWS) + + Rubber stamped by Geoff Garen + + * assembler/MacroAssemblerCodeRef.h: + +2012-01-30 Gavin Barraclough <barraclough@apple.com> + + Unreviewed build fix for interpreter builds. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecode/CodeBlock.h: + (CodeBlock): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * tools/CodeProfile.cpp: + (JSC::CodeProfile::sample): + +2012-01-30 Gavin Barraclough <barraclough@apple.com> + + Unreviewed build fix following bug#76855 + + * JavaScriptCore.exp: + +2012-01-30 Michael Saboff <msaboff@apple.com> + + CaseFoldingHash::hash() doesn't handle 8 bit strings directly + https://bugs.webkit.org/show_bug.cgi?id=76652 + + Reviewed by Andreas Kling. + + * wtf/text/StringHash.h: + (WTF::CaseFoldingHash::hash): Added 8 bit string code path. + +2012-01-30 Michael Saboff <msaboff@apple.com> + + stringProtoFuncReplace converts 8 bit strings to 16 bit during replacement + https://bugs.webkit.org/show_bug.cgi?id=76651 + + Reviewed by Geoffrey Garen. + + Made local function substituteBackreferencesSlow a template function + based on character width. Cleaned up getCharacters() in both UString + and StringImpl. Changed getCharacters<UChar> to up convert an 8 bit + string to 16 bits if necessary. + + * runtime/StringPrototype.cpp: + (JSC::substituteBackreferencesSlow): + (JSC::substituteBackreferences): + * runtime/UString.h: + (JSC::LChar): + (JSC::UChar): + * wtf/text/StringImpl.h: + (WTF::UChar): + +2012-01-30 Gavin Barraclough <barraclough@apple.com> + + Clean up putDirect + https://bugs.webkit.org/show_bug.cgi?id=76232 + + Reviewed by Sam Weinig. + + Part 3 - merge op_put_getter & op_put_setter. + + Putting these separately is inefficient (and makes future optimiation, + e.g. making GetterSetter immutable) harder. Change to emit a single + op_put_getter_setter bytecode op. Ultimately we should probably be + able to merge this with put direct, to create a common op to initialize + object literal properties. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + (JSC): + (): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitPutGetterSetter): + * bytecompiler/BytecodeGenerator.h: + (BytecodeGenerator): + * bytecompiler/NodesCodegen.cpp: + (JSC::PropertyListNode::emitBytecode): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + (JIT): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_put_getter_setter): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_put_getter_setter): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * jit/JITStubs.h: + (): + * runtime/JSObject.cpp: + (JSC::JSObject::putDirectVirtual): + (JSC::JSObject::putDirectAccessor): + (JSC): + (JSC::putDescriptor): + (JSC::JSObject::defineOwnProperty): + * runtime/JSObject.h: + (): + (JSC::JSObject::putDirectInternal): + (JSC::JSObject::putDirect): + (JSC::JSObject::putDirectWithoutTransition): + +2012-01-30 Michael Saboff <msaboff@apple.com> + + Dromaeo tests call parseSimpleLengthValue() on 8 bit strings + https://bugs.webkit.org/show_bug.cgi?id=76649 + + Reviewed by Geoffrey Garen. + + * JavaScriptCore.exp: Added export for charactersToDouble. + +2012-01-30 Michael Saboff <msaboff@apple.com> + + WebCore decodeEscapeSequences unnecessarily converts 8 bit strings to 16 bit when decoding. + https://bugs.webkit.org/show_bug.cgi?id=76648 + + Reviewed by Geoffrey Garen. + + Added a new overloaded append member that takes a String& argument, an offest + and a length to do direct sub string appending to a StringBuilder. + + * wtf/text/StringBuilder.h: + (WTF::StringBuilder::append): + +2012-01-29 Zoltan Herczeg <zherczeg@webkit.org> + + Custom written CSS lexer + https://bugs.webkit.org/show_bug.cgi?id=70107 + + Reviewed by Antti Koivisto and Oliver Hunt. + + Add new helper functions for the custom written CSS lexer. + + * wtf/ASCIICType.h: + (WTF::toASCIILowerUnchecked): + (WTF): + (WTF::isASCIIAlphaCaselessEqual): + +2012-01-29 Filip Pizlo <fpizlo@apple.com> + + REGRESSION (r105576-r105582): Web Inspector Crash in JSC::JSValue::toString(JSC::ExecState*) const + https://bugs.webkit.org/show_bug.cgi?id=77146 + <rdar://problem/10770586> + + Reviewed by Oliver Hunt. + + The old JIT expects that the result of the last operation is in the lastResultRegister. The DFG JIT is + designed to correctly track the lastResultRegister by looking at SetLocal nodes. However, when the DFG + JIT inlines a code block, it forgets that the inlined code block's result would have been placed in the + lastResultRegister. Hence if we OSR exit on the first node following the end of an inlined code block + that had a return value, and that first node uses the return value, the old JIT will get massively + confused. This patch takes a surgical approach: instead of making the DFG smarter, it makes the old + JIT slightly dumber. + + * jit/JITCall.cpp: + (JSC::JIT::emit_op_call_put_result): + +2012-01-29 Filip Pizlo <fpizlo@apple.com> + + Build fix for Mac non-x64 platforms. + + * tools/CodeProfiling.cpp: + (JSC): + +2012-01-28 Gavin Barraclough <barraclough@apple.com> + + Reserve 'let' + https://bugs.webkit.org/show_bug.cgi?id=77293 + + Rubber stamped by Oliver Hunt. + + 'let' may become a keyword in ES6. We're going to try experimentally reserving it, + to see if this breaks the web. + + * parser/Keywords.table: + +2012-01-27 Gavin Barraclough <barraclough@apple.com> + + Implement a JIT-code aware sampling profiler for JSC + https://bugs.webkit.org/show_bug.cgi?id=76855 + + Reviewed by Oliver Hunt. + + To enable the profiler, set the JSC_CODE_PROFILING environment variable to + 1 (no tracing the C stack), 2 (trace one level of C code) or 3 (recursively + trace all samples). + + The profiler requires -fomit-frame-pointer to be removed from the build flags. + + * JavaScriptCore.exp: + - Removed an export. + * JavaScriptCore.xcodeproj/project.pbxproj: + - Added new files + * bytecode/CodeBlock.cpp: + - For baseline codeblocks, cache the result of canCompileWithDFG. + * bytecode/CodeBlock.h: + - For baseline codeblocks, cache the result of canCompileWithDFG. + * jit/ExecutableAllocator.cpp: + (JSC::ExecutableAllocator::initializeAllocator): + - Notify the profiler when the allocator is created. + (JSC::ExecutableAllocator::allocate): + - Inform the allocated of the ownerUID. + * jit/ExecutableAllocatorFixedVMPool.cpp: + (JSC::ExecutableAllocator::initializeAllocator): + - Notify the profiler when the allocator is created. + (JSC::ExecutableAllocator::allocate): + - Inform the allocated of the ownerUID. + * jit/JITStubs.cpp: + - If profiling, don't mask the return address in JIT code. + (We do so to provide nicer backtraces in debug builds). + * runtime/Completion.cpp: + (JSC::evaluate): + - Notify the profiler of script evaluations. + * tools: Added. + * tools/CodeProfile.cpp: Added. + (JSC::symbolName): + - Helper function to get the name of a symbol in the framework. + (JSC::truncateTrace): + - Helper to truncate traces into methods know to have uninformatively deep stacks. + (JSC::CodeProfile::sample): + - Record a stack trace classifying samples. + (JSC::CodeProfile::report): + - {Print profiler output. + * tools/CodeProfile.h: Added. + - new class, captures a set of samples associated with an evaluated script, + and nested to record samples from subscripts. + * tools/CodeProfiling.cpp: Added. + (JSC::CodeProfiling::profilingTimer): + - callback fired then a timer event occurs. + (JSC::CodeProfiling::notifyAllocator): + - called when the executable allocator is constructed. + (JSC::CodeProfiling::getOwnerUIDForPC): + - helper to lookup the codeblock from an address in JIT code + (JSC::CodeProfiling::begin): + - enter a profiling scope. + (JSC::CodeProfiling::end): + - exit a profiling scope. + * tools/CodeProfiling.h: Added. + - new class, instantialed from Completion to define a profiling scope. + * tools/ProfileTreeNode.h: Added. + - new class, used to construct a tree of samples. + * tools/TieredMMapArray.h: Added. + - new class, a malloc-free vector (can be used while the main thread is suspended, + possibly holding the malloc heap lock). + * wtf/MetaAllocator.cpp: + (WTF::MetaAllocatorHandle::MetaAllocatorHandle): + (WTF::MetaAllocator::allocate): + - Allow allocation handles to track information about their owner. + * wtf/MetaAllocator.h: + (MetaAllocator): + - Allow allocation handles to track information about their owner. + * wtf/MetaAllocatorHandle.h: + (MetaAllocatorHandle): + (WTF::MetaAllocatorHandle::ownerUID): + - Allow allocation handles to track information about their owner. + * wtf/OSAllocator.h: + (WTF::OSAllocator::reallocateCommitted): + - reallocate an existing, committed memory allocation. + +2012-01-28 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r106187. + http://trac.webkit.org/changeset/106187 + https://bugs.webkit.org/show_bug.cgi?id=77276 + + The last rollout was a false charge. (Requested by morrita on + #webkit). + + * runtime/ExceptionHelpers.h: + (InterruptedExecutionError): + * runtime/JSBoundFunction.h: + (JSBoundFunction): + * runtime/RegExp.h: + (RegExp): + * runtime/RegExpMatchesArray.h: + (RegExpMatchesArray): + +2012-01-28 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r106151. + http://trac.webkit.org/changeset/106151 + https://bugs.webkit.org/show_bug.cgi?id=77275 + + may break windows build (Requested by morrita on #webkit). + + * runtime/ExceptionHelpers.h: + (InterruptedExecutionError): + * runtime/JSBoundFunction.h: + (JSBoundFunction): + * runtime/RegExp.h: + (RegExp): + * runtime/RegExpMatchesArray.h: + (RegExpMatchesArray): + +2012-01-28 Filip Pizlo <fpizlo@apple.com> + + GC invoked while doing an old JIT property storage reallocation may lead + to an object that refers to a dead structure + https://bugs.webkit.org/show_bug.cgi?id=77273 + <rdar://problem/10770565> + + Reviewed by Gavin Barraclough. + + The put_by_id transition was already saving the old structure by virtue of + having the object on the stack, so that wasn't going to get deleted. But the + new structure was unprotected in the transition. I've now changed the + transition code to save the new structure, ensuring that the GC will know it + to be marked if invoked from within put_by_id_transition_realloc. + + * jit/JITPropertyAccess.cpp: + (JSC::JIT::privateCompilePutByIdTransition): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::privateCompilePutByIdTransition): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * jit/JITStubs.h: + (JSC): + (): + +2012-01-27 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r106167. + http://trac.webkit.org/changeset/106167 + https://bugs.webkit.org/show_bug.cgi?id=77264 + + broke LayoutTests/fast/js/string-capitalization.html + (Requested by msaboff on #webkit). + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncToLowerCase): + (JSC::stringProtoFuncToUpperCase): + * wtf/text/StringImpl.cpp: + (WTF::StringImpl::upper): + +2012-01-27 Filip Pizlo <fpizlo@apple.com> + + Build fix for interpreter platforms. + + * interpreter/AbstractPC.cpp: + (JSC::AbstractPC::AbstractPC): + +2012-01-27 Michael Saboff <msaboff@apple.com> + + StringProtoFuncToUpperCase should call StringImpl::upper similar to StringProtoToLowerCase + https://bugs.webkit.org/show_bug.cgi?id=76647 + + Reviewed by Geoffrey Garen. + + Changed stringProtoFuncToUpperCase to call StringImpl::upper() is a manor similar + to stringProtoFuncToLowerCase(). Fixed StringImpl::upper() to handle the two + 8 bit characters that when converted to upper case become 16 bit characters. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncToLowerCase): Removed extra trailing whitespace. + (JSC::stringProtoFuncToUpperCase): + * wtf/text/StringImpl.cpp: + (WTF::StringImpl::upper): + +2012-01-27 Hajime Morita <morrita@google.com> + + [JSC] ThunkGenerators.cpp should hide its asm-defined symbols + https://bugs.webkit.org/show_bug.cgi?id=77244 + + Reviewed by Filip Pizlo. + + * jit/ThunkGenerators.cpp: Added HIDE_SYMBOLS() + * wtf/InlineASM.h: Moved some duplicated macros from ThunkGenerators.cpp + +2012-01-27 Simon Hausmann <simon.hausmann@nokia.com> + + [JSC] Asm-originated symbols should be marked as hidden + https://bugs.webkit.org/show_bug.cgi?id=77150 + + Reviewed by Filip Pizlo. + + * dfg/DFGOperations.cpp: The HIDE_SYMBOLS macros were present in the CPU(ARM) preprocessor branches, + but they were missing in the CPU(X86) and the CPU(X86_64) cases. + +2012-01-27 MORITA Hajime <morrita@google.com> + + [JSC] Some JS_EXPORTDATA may not be necessary. + https://bugs.webkit.org/show_bug.cgi?id=77145 + + Reviewed by Darin Adler. + + Removed JS_EXPORTDATA attributes whose attributing symbols are + not exported on Mac port. + + * runtime/ExceptionHelpers.h: + (InterruptedExecutionError): + * runtime/JSBoundFunction.h: + (JSBoundFunction): + * runtime/RegExp.h: + (RegExp): + * runtime/RegExpMatchesArray.h: + (RegExpMatchesArray): + +2012-01-27 MORITA Hajime <morrita@google.com> + + [WTF] WTFString.h has some extra JS_EXPORT_PRIVATEs + https://bugs.webkit.org/show_bug.cgi?id=77113 + + Reviewed by Darin Adler. + + * wtf/text/WTFString.h: Removed some WTF_EXPORT_PRIVATE attributes which we don't need to export. + +2012-01-27 Zeno Albisser <zeno@webkit.org> + + [Qt][Mac] Build fails after adding ICU support (r105997). + https://bugs.webkit.org/show_bug.cgi?id=77118 + + Use Apple code path for unicode date formats on mac. + + Reviewed by Tor Arne Vestbø. + + * runtime/DatePrototype.cpp: + (): + +2012-01-27 Carlos Garcia Campos <cgarcia@igalia.com> + + [GTK] Add a GKeyFile especialization to GOwnPtr + https://bugs.webkit.org/show_bug.cgi?id=77191 + + Reviewed by Martin Robinson. + + * wtf/gobject/GOwnPtr.cpp: + (WTF::GKeyFile): Implement freeOwnedGPtr for GKeyFile. + * wtf/gobject/GOwnPtr.h: Add GKeyFile template. + * wtf/gobject/GTypedefs.h: Add forward declaration for GKeyFile. + +2012-01-25 Yury Semikhatsky <yurys@chromium.org> + + Web Inspector: should be possible to open function declaration from script popover + https://bugs.webkit.org/show_bug.cgi?id=76913 + + Added display function name and source location to the popover in scripts panel. + Now when a function is hovered user can navigate to its definition. + + Reviewed by Pavel Feldman. + + * JavaScriptCore/JavaScriptCore.exp + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * runtime/JSFunction.h: + (JSFunction): + +2012-01-26 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Unreviewed. Build fix, wx uses the Mac ICU headers so we must match Mac behavior. + + * runtime/DatePrototype.cpp: + (): + +2012-01-26 Mark Hahnenberg <mhahnenberg@apple.com> + + Merge AllocationSpace into MarkedSpace + https://bugs.webkit.org/show_bug.cgi?id=77116 + + Reviewed by Geoffrey Garen. + + Merging AllocationSpace and MarkedSpace in preparation for future refactoring/enhancement to + MarkedSpace allocation. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.exp: + * JavaScriptCore.gypi: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * heap/AllocationSpace.cpp: Removed. + * heap/AllocationSpace.h: Removed. + * heap/BumpSpace.h: + (BumpSpace): + * heap/Heap.h: + (JSC::Heap::objectSpace): + (Heap): + (): + * heap/HeapBlock.h: + (): + * heap/MarkedSpace.cpp: + (JSC::MarkedSpace::tryAllocateHelper): + (JSC): + (JSC::MarkedSpace::tryAllocate): + (JSC::MarkedSpace::allocateSlowCase): + (JSC::MarkedSpace::allocateBlock): + (JSC::MarkedSpace::freeBlocks): + (TakeIfUnmarked): + (JSC::TakeIfUnmarked::TakeIfUnmarked): + (JSC::TakeIfUnmarked::operator()): + (JSC::TakeIfUnmarked::returnValue): + (JSC::MarkedSpace::shrink): + (GatherDirtyCells): + (JSC::GatherDirtyCells::returnValue): + (JSC::GatherDirtyCells::GatherDirtyCells): + (JSC::GatherDirtyCells::operator()): + (JSC::MarkedSpace::gatherDirtyCells): + * heap/MarkedSpace.h: + (MarkedSpace): + (JSC::MarkedSpace::blocks): + (JSC::MarkedSpace::forEachCell): + (JSC): + (JSC::MarkedSpace::allocate): + +2012-01-26 Oliver Hunt <oliver@apple.com> + + MSVC bug fix. + <rdar://problem/10703671> MSVC generates bad code for enum compare. + + RS=Geoff + + Make bitfield large enough to work around MSVC's desire to make enums + signed types. + + * bytecode/CallLinkInfo.h: + (CallLinkInfo): + +2012-01-26 Filip Pizlo <fpizlo@apple.com> + + All DFG helpers that may call out to arbitrary JS code must know where they + were called from due to inlining and call stack walking + https://bugs.webkit.org/show_bug.cgi?id=77070 + <rdar://problem/10750834> + + Reviewed by Geoff Garen. + + Changed the DFG to always record a code origin index in the tag of the argument + count (which we previously left blank for the benefit of LLInt, but is still + otherwise unused by the DFG), so that if we ever need to walk the stack accurately + we know where to start. In particular, if the current ExecState* points several + semantic call frames away from the true semantic call frame because we had + performed inlining, having the code origin index recorded means that we can reify + those call frames as necessary to give runtime/library code an accurate view of + the current JS state. + + This required several large but mechanical changes: + + - Calling a function from the DFG now plants a store32 instruction to store the + code origin index. But the indices of code origins were previously picked by + the DFG::JITCompiler after code generation completed. I changed this somewhat; + even though the code origins are put into the CodeBlock after code gen, the + code gen now knows a priori what their indices will be. Extensive assertions + are in place to ensure that the two don't get out of sync, in the form of the + DFG::CallBeginToken. Note that this mechanism has almost no effect on JS calls; + those don't need the code origin index set in the call frame because we can get + it by doing a binary search on the return PC. + + - Stack walking now always calls trueCallFrame() first before beginning the walk, + since even the top call frame may be wrong. It still calls trueCallerFrame() as + before to get to the next frame, though trueCallerFrame() is now mostly a + wrapper around callerFrame()->trueCallFrame(). + + - Because the mechanism for getting the code origin of a call frame is bimodal + (either the call frame knows its code origin because the code origin index was + set, or it's necessary to use the callee frame's return PC), I put in extra + mechanisms to determine whether your caller, or your callee, corresponds to + a call out of C++ code. Previously we just had the host call flag, but this is + insufficient as it does not cover the case of someone calling JSC::call(). But + luckily we can determine this just by looking at the return PC: if the return + PC is in range of the ctiTrampiline, then two things are true: this call + frame's PC will tell you nothing about where you came from in your caller, and + the caller already knows where it's at because it must have set the code origin + index (unless it's not DFG code, in which case we don't care because there is + no inlining to worry about). + + - During testing this revealed a simple off-by-one goof in DFG::ByteCodeParser's + inlining code, so I fixed it. + + - Finally because I was tired of doing random #if's for checking if I should be + passing around an Instruction* or a ReturnAddressPtr, I created a class called + AbstractPC that holds whatever notion of a PC is appropriate for the current + execution environment. It's designed to work gracefully even if both the + interpreter and the JIT are compiled in, and should integrate nicely with the + LLInt. + + This is neutral on all benchmarks and fixes some nasty corner-case regressions of + evil code that uses combinations of getters/setters and function.arguments. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.exp: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * bytecode/CodeBlock.h: + (JSC::CodeBlock::codeOrigin): + (CodeBlock): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleInlining): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * dfg/DFGJITCompiler.h: + (CallBeginToken): + (JSC::DFG::CallBeginToken::CallBeginToken): + (JSC::DFG::CallBeginToken::assertCodeOriginIndex): + (JSC::DFG::CallBeginToken::assertNoCodeOriginIndex): + (DFG): + (JSC::DFG::CallExceptionRecord::CallExceptionRecord): + (CallExceptionRecord): + (JSC::DFG::JITCompiler::JITCompiler): + (JITCompiler): + (JSC::DFG::JITCompiler::nextCallBeginToken): + (JSC::DFG::JITCompiler::beginCall): + (JSC::DFG::JITCompiler::notifyCall): + (JSC::DFG::JITCompiler::addExceptionCheck): + (JSC::DFG::JITCompiler::addFastExceptionCheck): + * dfg/DFGOperations.cpp: + (): + * dfg/DFGRepatch.cpp: + (JSC::DFG::tryBuildGetByIDList): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::appendCallWithExceptionCheck): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * interpreter/AbstractPC.cpp: Added. + (JSC): + (JSC::AbstractPC::AbstractPC): + * interpreter/AbstractPC.h: Added. + (JSC): + (AbstractPC): + (JSC::AbstractPC::AbstractPC): + (JSC::AbstractPC::hasJITReturnAddress): + (JSC::AbstractPC::jitReturnAddress): + (JSC::AbstractPC::hasInterpreterReturnAddress): + (JSC::AbstractPC::interpreterReturnAddress): + (JSC::AbstractPC::isSet): + (JSC::AbstractPC::operator!): + (): + * interpreter/CallFrame.cpp: + (JSC): + (JSC::CallFrame::trueCallFrame): + (JSC::CallFrame::trueCallerFrame): + * interpreter/CallFrame.h: + (JSC::ExecState::abstractReturnPC): + (JSC::ExecState::codeOriginIndexForDFGWithInlining): + (ExecState): + (JSC::ExecState::trueCallFrame): + (JSC::ExecState::trueCallFrameFromVMCode): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::retrieveArgumentsFromVMCode): + (JSC::Interpreter::retrieveCallerFromVMCode): + (JSC::Interpreter::findFunctionCallFrameFromVMCode): + * interpreter/Interpreter.h: + (Interpreter): + (): + * jit/JITStubs.cpp: + (JSC): + (): + * jit/JITStubs.h: + (JSC): + (JSC::returnAddressIsInCtiTrampoline): + * runtime/JSFunction.cpp: + (JSC::JSFunction::argumentsGetter): + (JSC::JSFunction::callerGetter): + (JSC::JSFunction::getOwnPropertyDescriptor): + +2012-01-26 Peter Varga <pvarga@webkit.org> + + Fix build when VERBOSE_SPECULATION_FAILURE is enabled in DFG + https://bugs.webkit.org/show_bug.cgi?id=77104 + + Reviewed by Filip Pizlo. + + * dfg/DFGOperations.cpp: + (): + +2012-01-26 Michael Saboff <msaboff@apple.com> + + String::latin1() should take advantage of 8 bit strings + https://bugs.webkit.org/show_bug.cgi?id=76646 + + Reviewed by Geoffrey Garen. + + * wtf/text/WTFString.cpp: + (WTF::String::latin1): For 8 bit strings, use existing buffer + without conversion. + +2012-01-26 Michael Saboff <msaboff@apple.com> + + Dromaeo tests usage of StringImpl find routines cause 8->16 bit conversions + https://bugs.webkit.org/show_bug.cgi?id=76645 + + Reviewed by Geoffrey Garen. + + * wtf/text/StringImpl.cpp: + (WTF::equalIgnoringCase): New LChar version. + (WTF::findInner): New helper function. + (WTF::StringImpl::find): Added 8 bit path. + (WTF::reverseFindInner): New helper funciton. + (WTF::StringImpl::reverseFind): Added 8 bit path. + (WTF::StringImpl::reverseFindIgnoringCase): Added 8 bit path. + * wtf/text/StringImpl.h: + (WTF): + +2012-01-26 Csaba Osztrogonác <ossy@webkit.org> + + [Qt][Win] One more speculative buildfix after r105970. + + * JavaScriptCore.pri: + +2012-01-26 Csaba Osztrogonác <ossy@webkit.org> + + [Qt][Win] Speculative buildfix after r105970. + + * JavaScriptCore.pri: Link lgdi for DeleteObject() and DeleteDC(). + +2012-01-26 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r105982. + http://trac.webkit.org/changeset/105982 + https://bugs.webkit.org/show_bug.cgi?id=77090 + + breaks the world (Requested by WildFox on #webkit). + + * wtf/MainThread.cpp: + (WTF): + * wtf/Platform.h: + * wtf/mac/MainThreadMac.mm: + (WTF): + (WTF::registerGCThread): + (WTF::isMainThreadOrGCThread): + +2012-01-26 Roland Takacs <takacs.roland@stud.u-szeged.hu> + + [Qt] GC should be parallel on Qt platform + https://bugs.webkit.org/show_bug.cgi?id=73309 + + Reviewed by Zoltan Herczeg. + + These changes made the parallel gc feature available for Qt port. + The implementation of "registerGCThread" and "isMainThreadOrGCThread" + is moved from MainThreadMac.mm to the common MainThread.cpp to make + them available for other platforms. + + Measurement results: + V8 speed-up: 1.071x as fast [From: 746.1ms To: 696.4ms ] + WindScorpion speed-up: 1.082x as fast [From: 3490.4ms To: 3226.7ms] + V8 Splay speed-up: 1.158x as fast [From: 145.8ms To: 125.9ms ] + + Tested on Intel(R) Core(TM) i5-2320 CPU @ 3.00GHz with 4-core. + + * wtf/MainThread.cpp: + (WTF): + (WTF::registerGCThread): + (WTF::isMainThreadOrGCThread): + * wtf/Platform.h: + * wtf/mac/MainThreadMac.mm: + +2012-01-26 Andy Estes <aestes@apple.com> + + REGRESSION (r105555): Incorrect use of OS() macro breaks OwnPtr when used with Win32 data types + https://bugs.webkit.org/show_bug.cgi?id=77073 + + Reviewed by Ryosuke Niwa. + + r105555 changed PLATFORM(WIN) to OS(WIN), but WTF_OS_WIN isn't defined. + This should have been changed to OS(WINDOWS). This causes the + preprocessor to strip out Win32 data type overrides for deleteOwnedPtr, + causing allocations made by Win32 to be deleted by fastmalloc. + + * wtf/OwnPtrCommon.h: + (WTF): Use OS(WINDOWS) instead of OS(WIN). + +2012-01-25 Mark Rowe <mrowe@apple.com> + + Attempted Mac build fix after r105939. + + * runtime/DatePrototype.cpp: Don't #include unicode/udat.h on Mac or iOS. + It isn't used on these platforms and isn't available in the ICU headers + for Mac. + +2012-01-25 Mark Rowe <mrowe@apple.com> + + Build in to an alternate location when USE_STAGING_INSTALL_PATH is set. + + <rdar://problem/10609417> Adopt USE_STAGING_INSTALL_PATH + + Reviewed by David Kilzer. + + * Configurations/Base.xcconfig: Define NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR, which contains + the path where JavaScriptCore is normally installed. Update JAVASCRIPTCORE_FRAMEWORKS_DIR + to point to the staged frameworks directory when USE_STAGING_INSTALL_PATH is set. + * Configurations/JavaScriptCore.xcconfig: Always set the framework's install name based on + the normal framework location. This prevents an incorrect install name from being used when + installing in to the staged frameworks directory. + +2012-01-25 Eli Fidler <efidler@rim.com> + + Implement Date.toLocaleString() using ICU + https://bugs.webkit.org/show_bug.cgi?id=76714 + + Reviewed by Darin Adler. + + * runtime/DatePrototype.cpp: + (JSC::formatLocaleDate): + +2012-01-25 Hajime Morita <morrita@google.com> + + ENABLE_SHADOW_DOM should be available via build-webkit --shadow-dom + https://bugs.webkit.org/show_bug.cgi?id=76863 + + Reviewed by Dimitri Glazkov. + + Added a feature flag. + + * Configurations/FeatureDefines.xcconfig: + +2012-01-25 Yong Li <yoli@rim.com> + + [BlackBerry] Implement OSAllocator::commit/decommit. + BlackBerry port should support virtual memory decommiting. + https://bugs.webkit.org/show_bug.cgi?id=77013 + + Reviewed by Rob Buis. + + * wtf/OSAllocatorPosix.cpp: + (WTF::OSAllocator::reserveUncommitted): + (WTF::OSAllocator::commit): + (WTF::OSAllocator::decommit): + * wtf/Platform.h: + +2012-01-24 Oliver Hunt <oliver@apple.com> + + Make DFG update topCallFrame + https://bugs.webkit.org/show_bug.cgi?id=76969 + + Reviewed by Filip Pizlo. + + Add NativeCallFrameTracer to manage topCallFrame assignment + in the DFG operations, and make use of it. + + * dfg/DFGOperations.cpp: + (JSC::DFG::operationPutByValInternal): + (): + * interpreter/Interpreter.h: + (JSC): + (NativeCallFrameTracer): + (JSC::NativeCallFrameTracer::NativeCallFrameTracer): + +2012-01-24 Filip Pizlo <fpizlo@apple.com> + + Inlining breaks call frame walking when the walking is done from outside the inlinee, + but inside a code block that had inlining + https://bugs.webkit.org/show_bug.cgi?id=76978 + <rdar://problem/10720904> + + Reviewed by Oliver Hunt. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::codeOriginForReturn): + * interpreter/CallFrame.cpp: + (JSC::CallFrame::trueCallerFrame): + +2012-01-24 Gavin Barraclough <barraclough@apple.com> + + https://bugs.webkit.org/show_bug.cgi?id=76855 + Implement a JIT-code aware sampling profiler for JSC + + Reviewed by Oliver Hunt. + + Add support to MetaAllocator.cpp to track all live handles in a map, + allowing lookup based on any address within the allocation. + + * wtf/MetaAllocator.cpp: + (WTF::MetaAllocatorTracker::notify): + (WTF::MetaAllocatorTracker::release): + - Track live handle objects in a map. + (WTF::MetaAllocator::release): + - Removed support for handles with null m_allocator (no longer used). + - Notify the tracker of handles being released. + (WTF::MetaAllocatorHandle::~MetaAllocatorHandle): + - Moved functionality out into MetaAllocator::release. + (WTF::MetaAllocatorHandle::shrink): + - Removed support for handles with null m_allocator (no longer used). + (WTF::MetaAllocator::MetaAllocator): + - Initialize m_tracker. + (WTF::MetaAllocator::allocate): + - Notify the tracker of new allocations. + * wtf/MetaAllocator.h: + (WTF::MetaAllocatorTracker::find): + - Lookup a MetaAllocatorHandle based on an address inside the allocation. + (WTF::MetaAllocator::trackAllocations): + - Register a callback object to track allocation state. + * wtf/MetaAllocatorHandle.h: + - Remove unused createSelfManagedHandle/constructor. + (WTF::MetaAllocatorHandle::key): + - Added, for use in RedBlackTree. + +2012-01-24 Mark Hahnenberg <mhahnenberg@apple.com> + + Use copying collector for out-of-line JSObject property storage + https://bugs.webkit.org/show_bug.cgi?id=76665 + + Reviewed by Geoffrey Garen. + + * runtime/JSObject.cpp: + (JSC::JSObject::visitChildren): Changed to use copyAndAppend whenever the property storage is out-of-line. + Also added a temporary variable to avoid warnings from GCC. + (JSC::JSObject::allocatePropertyStorage): Changed to use tryAllocateStorage/tryReallocateStorage as opposed to + operator new. Also added a temporary variable to avoid warnings from GCC. + * runtime/JSObject.h: + +2012-01-24 Geoffrey Garen <ggaren@apple.com> + + JSValue::toString() should return a JSString* instead of a UString + https://bugs.webkit.org/show_bug.cgi?id=76861 + + Fixed two failing layout tests after my last patch. + + Reviewed by Gavin Barraclough. + + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncSort): Call value() after calling toString(), as + in all other cases. + + I missed this case because the JSString* type has a valid operator<, + so the compiler didn't complain. + +2012-01-24 Kenichi Ishibashi <bashi@chromium.org> + + [V8] Add Uint8ClampedArray support + https://bugs.webkit.org/show_bug.cgi?id=76803 + + Reviewed by Kenneth Russell. + + * wtf/ArrayBufferView.h: + (WTF::ArrayBufferView::isUnsignedByteClampedArray): Added. + * wtf/Uint8ClampedArray.h: + (WTF::Uint8ClampedArray::isUnsignedByteClampedArray): Overridden to return true. + +2012-01-23 Carlos Garcia Campos <cgarcia@igalia.com> + + [GTK] Add WebKitDownload to WebKit2 GTK+ API + https://bugs.webkit.org/show_bug.cgi?id=72949 + + Reviewed by Martin Robinson. + + * wtf/gobject/GOwnPtr.cpp: + (WTF::GTimer): Use g_timer_destroy() to free a GTimer. + * wtf/gobject/GOwnPtr.h: Add GTimer template. + * wtf/gobject/GTypedefs.h: Add GTimer forward declaration. + +2012-01-24 Ilya Tikhonovsky <loislo@chromium.org> + + Unreviewed build fix for Qt LinuxSH4 build after r105698. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + +2012-01-23 Geoffrey Garen <ggaren@apple.com> + + JSValue::toString() should return a JSString* instead of a UString + https://bugs.webkit.org/show_bug.cgi?id=76861 + + Reviewed by Gavin Barraclough. + + This makes the common case -- toString() on a string -- faster and + inline-able. (Not a measureable speedup, but we can now remove a bunch + of duplicate hand-rolled code for this optimization.) + + This also clarifies the boundary between "C++ strings" and "JS strings". + + In all cases other than true, false, null, undefined, and multi-digit + numbers, the JS runtime was just retrieving a UString from a JSString, + so returning a JSString* is strictly better. In the other cases, we can + optimize to avoid creating a new JSString if we care to, but it doesn't + seem to be a big deal. + + * JavaScriptCore.exp: Export! + + * jsc.cpp: + (functionPrint): + (functionDebug): + (functionRun): + (functionLoad): + (functionCheckSyntax): + (runWithScripts): + (runInteractive): + * API/JSValueRef.cpp: + (JSValueToStringCopy): + * bytecode/CodeBlock.cpp: + (JSC::valueToSourceString): Call value() after calling toString(), to + convert from "JS string" (JSString*) to "C++ string" (UString), since + toString() no longer returns a "C++ string". + + * dfg/DFGOperations.cpp: + (JSC::DFG::operationValueAddNotNumber): + * jit/JITStubs.cpp: + (op_add): Updated for removal of toPrimitiveString(): + all '+' operands can use toString(), except for object operands, which + need to take a slow path to call toPrimitive(). + + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncToString): + (JSC::arrayProtoFuncToLocaleString): + (JSC::arrayProtoFuncJoin): + (JSC::arrayProtoFuncPush): + * runtime/CommonSlowPaths.h: + (JSC::CommonSlowPaths::opIn): + * runtime/DateConstructor.cpp: + (JSC::dateParse): + * runtime/DatePrototype.cpp: + (JSC::formatLocaleDate): Call value() after calling toString(), as above. + + * runtime/ErrorInstance.h: + (JSC::ErrorInstance::create): Simplified down to one canonical create() + function, to make string handling easier. + + * runtime/ErrorPrototype.cpp: + (JSC::errorProtoFuncToString): + * runtime/ExceptionHelpers.cpp: + (JSC::createInvalidParamError): + (JSC::createNotAConstructorError): + (JSC::createNotAFunctionError): + (JSC::createNotAnObjectError): + * runtime/FunctionConstructor.cpp: + (JSC::constructFunctionSkippingEvalEnabledCheck): + * runtime/FunctionPrototype.cpp: + (JSC::functionProtoFuncBind): + * runtime/JSArray.cpp: + (JSC::JSArray::sort): Call value() after calling toString(), as above. + + * runtime/JSCell.cpp: + * runtime/JSCell.h: Removed JSCell::toString() because JSValue does this + job now. Doing it in JSCell is slower (requires extra type checking), and + creates the misimpression that language-defined toString() behavior is + an implementation detail of JSCell. + + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::encode): + (JSC::decode): + (JSC::globalFuncEval): + (JSC::globalFuncParseInt): + (JSC::globalFuncParseFloat): + (JSC::globalFuncEscape): + (JSC::globalFuncUnescape): Call value() after calling toString(), as above. + + * runtime/JSONObject.cpp: + (JSC::unwrapBoxedPrimitive): + (JSC::Stringifier::Stringifier): + (JSC::JSONProtoFuncParse): Removed some manual optimization that toString() + takes care of. + + * runtime/JSObject.cpp: + (JSC::JSObject::toString): + * runtime/JSObject.h: Updated to return JSString*. + + * runtime/JSString.cpp: + * runtime/JSString.h: + (JSC::JSValue::toString): Removed, since I removed JSCell::toString(). + + * runtime/JSValue.cpp: + (JSC::JSValue::toStringSlowCase): Removed toPrimitiveString(), and re- + spawned toStringSlowCase() from its zombie corpse, since toPrimitiveString() + basically did what we want all the time. (Note that the toPrimitive() + preference changes from NoPreference to PreferString, because that's + how ToString is defined in the language. op_add does not want this behavior.) + + * runtime/NumberPrototype.cpp: + (JSC::numberProtoFuncToString): + (JSC::numberProtoFuncToLocaleString): A little simpler, now that toString() + returns a JSString*. + + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorGetOwnPropertyDescriptor): + (JSC::objectConstructorDefineProperty): + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncHasOwnProperty): + (JSC::objectProtoFuncDefineGetter): + (JSC::objectProtoFuncDefineSetter): + (JSC::objectProtoFuncLookupGetter): + (JSC::objectProtoFuncLookupSetter): + (JSC::objectProtoFuncPropertyIsEnumerable): More calls to value(), as above. + + * runtime/Operations.cpp: + (JSC::jsAddSlowCase): Need to check for object before taking the toString() + fast path becuase adding an object to a string requires calling toPrimitive() + on the object, not toString(). (They differ in their preferred conversion + type.) + + * runtime/Operations.h: + (JSC::jsString): + (JSC::jsStringFromArguments): This code gets simpler, now that toString() + does the right thing. + + (JSC::jsAdd): Now checks for object, just like jsAddSlowCase(). + + * runtime/RegExpConstructor.cpp: + (JSC::setRegExpConstructorInput): + (JSC::constructRegExp): + * runtime/RegExpObject.cpp: + (JSC::RegExpObject::match): + * runtime/RegExpPrototype.cpp: + (JSC::regExpProtoFuncCompile): + (JSC::regExpProtoFuncToString): More calls to value(), as above. + + * runtime/StringConstructor.cpp: + (JSC::constructWithStringConstructor): + (JSC::callStringConstructor): This code gets simpler, now that toString() + does the right thing. + + * runtime/StringPrototype.cpp: + (JSC::replaceUsingRegExpSearch): + (JSC::replaceUsingStringSearch): + (JSC::stringProtoFuncReplace): + (JSC::stringProtoFuncCharAt): + (JSC::stringProtoFuncCharCodeAt): + (JSC::stringProtoFuncConcat): + (JSC::stringProtoFuncIndexOf): + (JSC::stringProtoFuncLastIndexOf): + (JSC::stringProtoFuncMatch): + (JSC::stringProtoFuncSearch): + (JSC::stringProtoFuncSlice): + (JSC::stringProtoFuncSplit): + (JSC::stringProtoFuncSubstr): + (JSC::stringProtoFuncSubstring): + (JSC::stringProtoFuncToLowerCase): + (JSC::stringProtoFuncToUpperCase): + (JSC::stringProtoFuncLocaleCompare): + (JSC::stringProtoFuncBig): + (JSC::stringProtoFuncSmall): + (JSC::stringProtoFuncBlink): + (JSC::stringProtoFuncBold): + (JSC::stringProtoFuncFixed): + (JSC::stringProtoFuncItalics): + (JSC::stringProtoFuncStrike): + (JSC::stringProtoFuncSub): + (JSC::stringProtoFuncSup): + (JSC::stringProtoFuncFontcolor): + (JSC::stringProtoFuncFontsize): + (JSC::stringProtoFuncAnchor): + (JSC::stringProtoFuncLink): + (JSC::trimString): Some of this code gets simpler, now that toString() + does the right thing. More calls to value(), as above. + +2012-01-23 Luke Macpherson <macpherson@chromium.org> + + Unreviewed, rolling out r105676. + http://trac.webkit.org/changeset/105676 + https://bugs.webkit.org/show_bug.cgi?id=76665 + + Breaks build on max due to compile warnings. + + * runtime/JSObject.cpp: + (JSC::JSObject::finalize): + (JSC::JSObject::visitChildren): + (JSC::JSObject::allocatePropertyStorage): + * runtime/JSObject.h: + +2012-01-23 Mark Hahnenberg <mhahnenberg@apple.com> + + Use copying collector for out-of-line JSObject property storage + https://bugs.webkit.org/show_bug.cgi?id=76665 + + Reviewed by Geoffrey Garen. + + * runtime/JSObject.cpp: + (JSC::JSObject::visitChildren): Changed to use copyAndAppend whenever the property storage is out-of-line. + (JSC::JSObject::allocatePropertyStorage): Changed to use tryAllocateStorage/tryReallocateStorage as opposed to + operator new. + * runtime/JSObject.h: + +2012-01-23 Brian Weinstein <bweinstein@apple.com> + + More build fixing after r105646. + + * JavaScriptCore.exp: + +2012-01-23 Gavin Barraclough <barraclough@apple.com> + + https://bugs.webkit.org/show_bug.cgi?id=76855 + Implement a JIT-code aware sampling profiler for JSC + + Reviewed by Geoff Garen. + + Step 2: generalize RedBlackTree. The profiler is going to want tio use + a RedBlackTree, allow this class to work with subclasses of + RedBlackTree::Node, Node should not need to know the names of the m_key + and m_value fields (the subclass can provide a key() accessor), and + RedBlackTree does not need to know anything about ValueType. + + * JavaScriptCore.exp: + * wtf/MetaAllocator.cpp: + (WTF::MetaAllocator::findAndRemoveFreeSpace): + (WTF::MetaAllocator::debugFreeSpaceSize): + (WTF::MetaAllocator::addFreeSpace): + * wtf/MetaAllocator.h: + (WTF::MetaAllocator::FreeSpaceNode::FreeSpaceNode): + (WTF::MetaAllocator::FreeSpaceNode::key): + * wtf/MetaAllocatorHandle.h: + (WTF::MetaAllocatorHandle::key): + * wtf/RedBlackTree.h: + (WTF::RedBlackTree::Node::successor): + (WTF::RedBlackTree::Node::predecessor): + (WTF::RedBlackTree::Node::parent): + (WTF::RedBlackTree::Node::setParent): + (WTF::RedBlackTree::Node::left): + (WTF::RedBlackTree::Node::setLeft): + (WTF::RedBlackTree::Node::right): + (WTF::RedBlackTree::Node::setRight): + (WTF::RedBlackTree::insert): + (WTF::RedBlackTree::remove): + (WTF::RedBlackTree::findExact): + (WTF::RedBlackTree::findLeastGreaterThanOrEqual): + (WTF::RedBlackTree::findGreatestLessThanOrEqual): + (WTF::RedBlackTree::first): + (WTF::RedBlackTree::last): + (WTF::RedBlackTree::size): + (WTF::RedBlackTree::treeMinimum): + (WTF::RedBlackTree::treeMaximum): + (WTF::RedBlackTree::treeInsert): + (WTF::RedBlackTree::leftRotate): + (WTF::RedBlackTree::rightRotate): + (WTF::RedBlackTree::removeFixup): + +2012-01-23 Andy Estes <aestes@apple.com> + + Fix the build after r105635. + + * JavaScriptCore.exp: + +2012-01-23 Mark Hahnenberg <mhahnenberg@apple.com> + + Remove StackBounds from JSGlobalData + https://bugs.webkit.org/show_bug.cgi?id=76310 + + Reviewed by Sam Weinig. + + Removed StackBounds and the stack() function from JSGlobalData since it no + longer accessed any members of JSGlobalData. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::addCurrentThread): + (JSC::MachineThreads::gatherFromCurrentThread): + * parser/Parser.cpp: + (JSC::::Parser): + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + * runtime/JSGlobalData.h: + +2012-01-23 Gavin Barraclough <barraclough@apple.com> + + Implement a JIT-code aware sampling profiler for JSC + https://bugs.webkit.org/show_bug.cgi?id=76855 + + Rubber stanmped by Geoff Garen. + + Mechanical change - pass CodeBlock through to the executable allocator, + such that we will be able to map ranges of JIT code back to their owner. + + * assembler/ARMAssembler.cpp: + (JSC::ARMAssembler::executableCopy): + * assembler/ARMAssembler.h: + * assembler/AssemblerBuffer.h: + (JSC::AssemblerBuffer::executableCopy): + * assembler/AssemblerBufferWithConstantPool.h: + (JSC::AssemblerBufferWithConstantPool::executableCopy): + * assembler/LinkBuffer.h: + (JSC::LinkBuffer::LinkBuffer): + (JSC::LinkBuffer::linkCode): + * assembler/MIPSAssembler.h: + (JSC::MIPSAssembler::executableCopy): + * assembler/SH4Assembler.h: + (JSC::SH4Assembler::executableCopy): + * assembler/X86Assembler.h: + (JSC::X86Assembler::executableCopy): + (JSC::X86Assembler::X86InstructionFormatter::executableCopy): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::compile): + (JSC::DFG::JITCompiler::compileFunction): + * dfg/DFGOSRExitCompiler.cpp: + * dfg/DFGRepatch.cpp: + (JSC::DFG::generateProtoChainAccessStub): + (JSC::DFG::tryCacheGetByID): + (JSC::DFG::tryBuildGetByIDList): + (JSC::DFG::tryCachePutByID): + * dfg/DFGThunks.cpp: + (JSC::DFG::osrExitGenerationThunkGenerator): + * jit/ExecutableAllocator.cpp: + (JSC::ExecutableAllocator::allocate): + * jit/ExecutableAllocator.h: + * jit/ExecutableAllocatorFixedVMPool.cpp: + (JSC::ExecutableAllocator::allocate): + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JITOpcodes.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + (JSC::JIT::privateCompileCTINativeCall): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::stringGetByValStubGenerator): + (JSC::JIT::privateCompilePutByIdTransition): + (JSC::JIT::privateCompilePatchGetArrayLength): + (JSC::JIT::privateCompileGetByIdProto): + (JSC::JIT::privateCompileGetByIdSelfList): + (JSC::JIT::privateCompileGetByIdProtoList): + (JSC::JIT::privateCompileGetByIdChainList): + (JSC::JIT::privateCompileGetByIdChain): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::stringGetByValStubGenerator): + (JSC::JIT::privateCompilePutByIdTransition): + (JSC::JIT::privateCompilePatchGetArrayLength): + (JSC::JIT::privateCompileGetByIdProto): + (JSC::JIT::privateCompileGetByIdSelfList): + (JSC::JIT::privateCompileGetByIdProtoList): + (JSC::JIT::privateCompileGetByIdChainList): + (JSC::JIT::privateCompileGetByIdChain): + * jit/JITStubs.cpp: + * jit/SpecializedThunkJIT.h: + (JSC::SpecializedThunkJIT::finalize): + * yarr/YarrJIT.cpp: + (JSC::Yarr::YarrGenerator::compile): + +2012-01-23 Xianzhu Wang <wangxianzhu@chromium.org> + + Basic enhancements to StringBuilder + https://bugs.webkit.org/show_bug.cgi?id=67081 + + This change contains the following enhancements to StringBuilder, + for convenience, performance, testability, etc.: + - Change toStringPreserveCapacity() to const + - new public methods: capacity(), swap(), toAtomicString(), canShrink() + and append(const StringBuilder&) + - == and != opearators to compare StringBuilders and a StringBuilder/String + + Unit tests: Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp + + Reviewed by Darin Adler. + + * JavaScriptCore.exp: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * wtf/text/AtomicString.cpp: + (WTF::SubstringTranslator::hash): + (WTF::SubstringTranslator::equal): + (WTF::SubstringTranslator::translate): + (WTF::AtomicString::add): + (WTF::AtomicString::addSlowCase): + * wtf/text/AtomicString.h: + (WTF::AtomicString::AtomicString): + (WTF::AtomicString::add): + * wtf/text/StringBuilder.cpp: + (WTF::StringBuilder::reifyString): + (WTF::StringBuilder::resize): + (WTF::StringBuilder::canShrink): + (WTF::StringBuilder::shrinkToFit): + * wtf/text/StringBuilder.h: + (WTF::StringBuilder::append): + (WTF::StringBuilder::toString): + (WTF::StringBuilder::toStringPreserveCapacity): + (WTF::StringBuilder::toAtomicString): + (WTF::StringBuilder::isEmpty): + (WTF::StringBuilder::capacity): + (WTF::StringBuilder::is8Bit): + (WTF::StringBuilder::swap): + (WTF::equal): + (WTF::operator==): + (WTF::operator!=): + * wtf/text/StringImpl.h: + +2012-01-23 Carlos Garcia Campos <cgarcia@igalia.com> + + Unreviewed. Fix make distcheck. + + * GNUmakefile.list.am: Add missing files, remove deleted files and + fix indentation. + +2012-01-22 Filip Pizlo <fpizlo@apple.com> + + Build fix for non-DFG platforms that error out on warn-unused-parameter. + + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFor): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFor): + * bytecode/MethodCallLinkStatus.cpp: + (JSC::MethodCallLinkStatus::computeFor): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + +2012-01-22 Filip Pizlo <fpizlo@apple.com> + + Build fix for non-DFG platforms. + + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFor): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFor): + * bytecode/MethodCallLinkStatus.cpp: + (JSC::MethodCallLinkStatus::computeFor): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + +2012-01-20 Filip Pizlo <fpizlo@apple.com> + + DFG should not have code that directly decodes the states of old JIT inline + cache data structures + https://bugs.webkit.org/show_bug.cgi?id=76768 + + Reviewed by Sam Weinig. + + Introduced new classes (like GetByIdStatus) that encapsulate the set of things + that the DFG would like to know about property accesses and calls. Whereas it + previously got this information by directly decoding the data structures used + by the old JIT for inline caching, it now uses these classes, which do the work + for it. This should make it somewhat more straight forward to introduce new + ways of profiling the same information. + + Also hoisted StructureSet into bytecode/ from dfg/, because it's now used by + code in bytecode/. + + Making this work right involved carefully ensuring that the heuristics for + choosing how to handle property accesses was at least as good as what we had + before, since I completely restructured that code. Currently the performance + looks neutral. Since I rewrote the code I did change some things that I never + liked before, like previously if a put_bu_id had executed exactly once then + we'd compile it as if it had taken slow-path. Executing once is special because + then the inline cache is not baked in, so there is no information about how the + DFG should optimize the code. Now this is rationalized: if the put_by_id does + not offer enough information to be optimized (i.e. had executed 0 or 1 times) + then we turn it into a forced OSR exit (i.e. a patch point). However, get_by_id + still has the old behavior; I left it that way because I didn't want to make + too many changes at once. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * bytecode/CallLinkStatus.cpp: Added. + (JSC::CallLinkStatus::computeFor): + * bytecode/CallLinkStatus.h: Added. + (JSC::CallLinkStatus::CallLinkStatus): + (JSC::CallLinkStatus::isSet): + (JSC::CallLinkStatus::operator!): + (JSC::CallLinkStatus::couldTakeSlowPath): + (JSC::CallLinkStatus::callTarget): + * bytecode/GetByIdStatus.cpp: Added. + (JSC::GetByIdStatus::computeFor): + * bytecode/GetByIdStatus.h: Added. + (JSC::GetByIdStatus::GetByIdStatus): + (JSC::GetByIdStatus::state): + (JSC::GetByIdStatus::isSet): + (JSC::GetByIdStatus::operator!): + (JSC::GetByIdStatus::isSimpleDirect): + (JSC::GetByIdStatus::takesSlowPath): + (JSC::GetByIdStatus::makesCalls): + (JSC::GetByIdStatus::structureSet): + (JSC::GetByIdStatus::offset): + * bytecode/MethodCallLinkStatus.cpp: Added. + (JSC::MethodCallLinkStatus::computeFor): + * bytecode/MethodCallLinkStatus.h: Added. + (JSC::MethodCallLinkStatus::MethodCallLinkStatus): + (JSC::MethodCallLinkStatus::isSet): + (JSC::MethodCallLinkStatus::operator!): + (JSC::MethodCallLinkStatus::needsPrototypeCheck): + (JSC::MethodCallLinkStatus::structure): + (JSC::MethodCallLinkStatus::prototypeStructure): + (JSC::MethodCallLinkStatus::function): + (JSC::MethodCallLinkStatus::prototype): + * bytecode/PutByIdStatus.cpp: Added. + (JSC::PutByIdStatus::computeFor): + * bytecode/PutByIdStatus.h: Added. + (JSC::PutByIdStatus::PutByIdStatus): + (JSC::PutByIdStatus::state): + (JSC::PutByIdStatus::isSet): + (JSC::PutByIdStatus::operator!): + (JSC::PutByIdStatus::isSimpleReplace): + (JSC::PutByIdStatus::isSimpleTransition): + (JSC::PutByIdStatus::takesSlowPath): + (JSC::PutByIdStatus::oldStructure): + (JSC::PutByIdStatus::newStructure): + (JSC::PutByIdStatus::structureChain): + (JSC::PutByIdStatus::offset): + * bytecode/StructureSet.h: Added. + (JSC::StructureSet::StructureSet): + (JSC::StructureSet::clear): + (JSC::StructureSet::add): + (JSC::StructureSet::addAll): + (JSC::StructureSet::remove): + (JSC::StructureSet::contains): + (JSC::StructureSet::isSubsetOf): + (JSC::StructureSet::isSupersetOf): + (JSC::StructureSet::size): + (JSC::StructureSet::at): + (JSC::StructureSet::operator[]): + (JSC::StructureSet::last): + (JSC::StructureSet::predictionFromStructures): + (JSC::StructureSet::operator==): + (JSC::StructureSet::dump): + * dfg/DFGAbstractValue.h: + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGStructureSet.h: Removed. + +2012-01-20 Filip Pizlo <fpizlo@apple.com> + + JIT compilation should not require ExecState + https://bugs.webkit.org/show_bug.cgi?id=76729 + <rdar://problem/10731545> + + Reviewed by Gavin Barraclough. + + Changed the relevant JIT driver functions to take JSGlobalData& instead of + ExecState*, since really they just needed the global data. + + * dfg/DFGDriver.cpp: + (JSC::DFG::compile): + (JSC::DFG::tryCompile): + (JSC::DFG::tryCompileFunction): + * dfg/DFGDriver.h: + (JSC::DFG::tryCompile): + (JSC::DFG::tryCompileFunction): + * jit/JITDriver.h: + (JSC::jitCompileIfAppropriate): + (JSC::jitCompileFunctionIfAppropriate): + * runtime/Executable.cpp: + (JSC::EvalExecutable::compileInternal): + (JSC::ProgramExecutable::compileInternal): + (JSC::FunctionExecutable::compileForCallInternal): + (JSC::FunctionExecutable::compileForConstructInternal): + +2012-01-20 David Levin <levin@chromium.org> + + Make OwnPtr<HDC> work for the Chromium Windows port. + https://bugs.webkit.org/show_bug.cgi?id=76738 + + Reviewed by Jian Li. + + * JavaScriptCore.gyp/JavaScriptCore.gyp: Added OwnPtrWin.cpp to the + Chromium Windows build. + * wtf/OwnPtrCommon.h: Changed from platform WIN to OS WIN for + OwnPtr<HDC> and similar constructs. + +2012-01-19 Geoffrey Garen <ggaren@apple.com> + + Removed some regexp entry boilerplate code + https://bugs.webkit.org/show_bug.cgi?id=76687 + + Reviewed by Darin Adler. + + 1% - 2% speedup on regexp tests, no change overall. + + * runtime/RegExp.cpp: + (JSC::RegExp::match): + - ASSERT that our startIndex is non-negative, because anything less + would be uncivilized. + + - ASSERT that our input is not the null string for the same reason. + + - No need to test for startOffset being past the end of the string, + since the regular expression engine will do this test for us. + + - No need to initialize the output vector, since the regular expression + engine will fill it in for us. + + * yarr/YarrInterpreter.cpp: + (JSC::Yarr::Interpreter::interpret): + * yarr/YarrJIT.cpp: + (JSC::Yarr::YarrGenerator::compile): + + RegExp used to do these jobs for us, but now we do them for ourselves + because it's a better separation of concerns, and the JIT can do them + more efficiently than C++ code: + + - Test for "past the end" before doing any matching -- otherwise + a* will match with zero length past the end of the string, which is wrong. + + - Initialize the output vector before doing any matching. + +2012-01-20 Filip Pizlo <fpizlo@apple.com> + + Build fix for no-DFG configuration. + Needed for <rdar://problem/10727689>. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitProfiledOpcode): + * jit/JIT.h: + (JSC::JIT::emitValueProfilingSite): + +2012-01-19 Filip Pizlo <fpizlo@apple.com> + + Bytecode instructions that may have value profiling should have a direct inline + link to the ValueProfile instance + https://bugs.webkit.org/show_bug.cgi?id=76682 + <rdar://problem/10727689> + + Reviewed by Sam Weinig. + + Each opcode that gets value profiled now has a link to its ValueProfile. This + required rationalizing the emission of value profiles for opcode combos, like + op_method_check/op_get_by_id and op_call/op_call_put_result. It only makes + sense for one of them to have a value profile link, and it makes most sense + for it to be the one that actually sets the result. The previous behavior was + to have op_method_check profile for op_get_by_id when they were used together, + but otherwise for op_get_by_id to have its own profiles. op_call already did + the right thing; all profiling was done by op_call_put_result. + + But rationalizing this code required breaking some of the natural boundaries + that the code had; for instance the code in DFG that emits a GetById in place + of both op_method_check and op_get_by_id must now know that it's the latter of + those that has the value profile, while the first of those constitutes the OSR + target. Hence each CodeOrigin must now have two bytecode indices - one for + OSR exit and one for profiling. + + Finally this change required some refiddling of our optimization heuristics, + because now all code blocks have "more instructions" due to the value profile + slots. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printGetByIdOp): + (JSC::CodeBlock::dump): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::valueProfileForBytecodeOffset): + * bytecode/CodeOrigin.h: + (JSC::CodeOrigin::CodeOrigin): + (JSC::CodeOrigin::bytecodeIndexForValueProfile): + * bytecode/Instruction.h: + (JSC::Instruction::Instruction): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitProfiledOpcode): + (JSC::BytecodeGenerator::emitResolve): + (JSC::BytecodeGenerator::emitGetScopedVar): + (JSC::BytecodeGenerator::emitResolveBase): + (JSC::BytecodeGenerator::emitResolveBaseForPut): + (JSC::BytecodeGenerator::emitResolveWithBase): + (JSC::BytecodeGenerator::emitResolveWithThis): + (JSC::BytecodeGenerator::emitGetById): + (JSC::BytecodeGenerator::emitGetByVal): + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitCallVarargs): + (JSC::BytecodeGenerator::emitConstruct): + * bytecompiler/BytecodeGenerator.h: + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::ByteCodeParser): + (JSC::DFG::ByteCodeParser::currentCodeOrigin): + (JSC::DFG::ByteCodeParser::addCall): + (JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit): + (JSC::DFG::ByteCodeParser::getPrediction): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::parse): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::valueProfileFor): + * jit/JIT.h: + (JSC::JIT::emitValueProfilingSite): + * jit/JITCall.cpp: + (JSC::JIT::emit_op_call_put_result): + * jit/JITCall32_64.cpp: + (JSC::JIT::emit_op_call_put_result): + * jit/JITInlineMethods.h: + (JSC::JIT::emitValueProfilingSite): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_resolve): + (JSC::JIT::emit_op_resolve_base): + (JSC::JIT::emit_op_resolve_skip): + (JSC::JIT::emit_op_resolve_global): + (JSC::JIT::emitSlow_op_resolve_global): + (JSC::JIT::emit_op_resolve_with_base): + (JSC::JIT::emit_op_resolve_with_this): + (JSC::JIT::emitSlow_op_resolve_global_dynamic): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_resolve): + (JSC::JIT::emit_op_resolve_base): + (JSC::JIT::emit_op_resolve_skip): + (JSC::JIT::emit_op_resolve_global): + (JSC::JIT::emitSlow_op_resolve_global): + (JSC::JIT::emit_op_resolve_with_base): + (JSC::JIT::emit_op_resolve_with_this): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emitSlow_op_get_by_val): + (JSC::JIT::emit_op_method_check): + (JSC::JIT::emitSlow_op_method_check): + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emitSlow_op_get_by_id): + (JSC::JIT::emit_op_get_scoped_var): + (JSC::JIT::emit_op_get_global_var): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_method_check): + (JSC::JIT::emitSlow_op_method_check): + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emitSlow_op_get_by_val): + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emitSlow_op_get_by_id): + (JSC::JIT::emit_op_get_scoped_var): + (JSC::JIT::emit_op_get_global_var): + * jit/JITStubCall.h: + (JSC::JITStubCall::callWithValueProfiling): + * runtime/Options.cpp: + (JSC::Options::initializeOptions): + +2012-01-20 ChangSeok Oh <shivamidow@gmail.com> + + undefined reference to symbol eina_module_free + https://bugs.webkit.org/show_bug.cgi?id=76681 + + Reviewed by Martin Robinson. + + eina_module_free has been used without including eina libraries after r104936. + + * wtf/PlatformEfl.cmake: Add EINA_LIBRARIES. + +2012-01-19 Tony Chang <tony@chromium.org> + + [chromium] Remove an obsolete comment about features.gypi + https://bugs.webkit.org/show_bug.cgi?id=76643 + + There can be only one features.gypi. + + Reviewed by James Robinson. + + * JavaScriptCore.gyp/JavaScriptCore.gyp: + +2012-01-19 Geoffrey Garen <ggaren@apple.com> + + Implicit creation of a regular expression should eagerly check for syntax errors + https://bugs.webkit.org/show_bug.cgi?id=76642 + + Reviewed by Oliver Hunt. + + This is a correctness fix and a slight optimization. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncMatch): + (JSC::stringProtoFuncSearch): Check for syntax errors because that's the + correct behavior. + + * runtime/RegExp.cpp: + (JSC::RegExp::match): ASSERT that we aren't a syntax error. (One line + of code change, many lines of indentation change.) + + Since we have no clients that try to match a RegExp that is a syntax error, + let's optimize out the check. + +2012-01-19 Mark Hahnenberg <mhahnenberg@apple.com> + + Implement a new allocator for backing stores + https://bugs.webkit.org/show_bug.cgi?id=75181 + + Reviewed by Filip Pizlo. + + We want to move away from using fastMalloc for the backing stores for + some of our objects (e.g. JSArray, JSObject, JSString, etc). These backing + stores have a nice property in that they only have a single owner (i.e. a + single pointer to them at any one time). One way that we can take advantage + of this property is to implement a simple bump allocator/copying collector, + which will run alongside our normal mark/sweep collector, that only needs to + update the single owner pointer rather than having to redirect an arbitrary + number of pointers in from-space to to-space. + + This plan can give us a number of benefits. We can beat fastMalloc in terms + of both performance and memory usage, we can track how much memory we're using + far more accurately than our rough estimation now through the use of + reportExtraMemoryCost, and we can allocate arbitrary size objects (as opposed + to being limited to size classes like we have been historically). This is also + another step toward moving away from lazy destruction, which will improve our memory footprint. + + We start by creating said allocator and moving the ArrayStorage for JSArray + to use it rather than fastMalloc. + + The design of the collector is as follows: + Allocation: + -The collector allocates 64KB chunks from the OS to use for object allocation. + -Each chunk contains an offset, a flag indicating if the block has been pinned, + and a payload, along with next and prev pointers so that they can be put in DoublyLinkedLists. + -Any allocation greater than 64KB gets its own separate oversize block, which + is managed separately from the rest. + -If the allocator receives a request for more than the remaining amount in the + current block, it grabs a fresh block. + -Grabbing a fresh block means grabbing one off of the global free list (which is now + shared between the mark/sweep allocator and the bump allocator) if there is one. + If there isn't a new one we do one of two things: allocate a new block from the OS + if we're not ready for a GC yet, or run a GC and then try again. If we still don't + have enough space after the GC, we allocate a new block from the OS. + + Garbage collection: + -At the start of garbage collection during conservative stack scanning, if we encounter + what appears to be a pointer to a bump-allocated block of memory, we pin that block so + that it will not be copied for this round of collection. + -We also pin any oversize blocks that we encounter, which effectively doubles as a + "mark bit" for that block. Any oversize blocks that aren't pinned at the end of copying + are given back to the OS. + -Marking threads are now also responsible for copying bump-allocated objects to newSpace + -Each marking thread has a private 64KB block into which it copies bump-allocated objects that it encounters. + -When that block fills up, the marking thread gives it back to the allocator and requests a new one. + -When all marking has concluded, each thread gives back its copy block, even if it isn't full. + -At the conclusion of copying (which is done by the end of the marking phase), we un-pin + any pinned blocks and give any blocks left in from-space to the global free list. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.gypi: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * heap/AllocationSpace.cpp: + (JSC::AllocationSpace::allocateSlowCase): + (JSC::AllocationSpace::allocateBlock): + (JSC::AllocationSpace::freeBlocks): + * heap/AllocationSpace.h: + (JSC::AllocationSpace::waterMark): + * heap/BumpBlock.h: Added. + (JSC::BumpBlock::BumpBlock): + * heap/BumpSpace.cpp: Added. + (JSC::BumpSpace::tryAllocateSlowCase): + * heap/BumpSpace.h: Added. + (JSC::BumpSpace::isInCopyPhase): + (JSC::BumpSpace::totalMemoryAllocated): + (JSC::BumpSpace::totalMemoryUtilized): + * heap/BumpSpaceInlineMethods.h: Added. + (JSC::BumpSpace::BumpSpace): + (JSC::BumpSpace::init): + (JSC::BumpSpace::contains): + (JSC::BumpSpace::pin): + (JSC::BumpSpace::startedCopying): + (JSC::BumpSpace::doneCopying): + (JSC::BumpSpace::doneFillingBlock): + (JSC::BumpSpace::recycleBlock): + (JSC::BumpSpace::getFreshBlock): + (JSC::BumpSpace::borrowBlock): + (JSC::BumpSpace::addNewBlock): + (JSC::BumpSpace::allocateNewBlock): + (JSC::BumpSpace::fitsInBlock): + (JSC::BumpSpace::fitsInCurrentBlock): + (JSC::BumpSpace::tryAllocate): + (JSC::BumpSpace::tryAllocateOversize): + (JSC::BumpSpace::allocateFromBlock): + (JSC::BumpSpace::tryReallocate): + (JSC::BumpSpace::tryReallocateOversize): + (JSC::BumpSpace::isOversize): + (JSC::BumpSpace::isPinned): + (JSC::BumpSpace::oversizeBlockFor): + (JSC::BumpSpace::blockFor): + * heap/ConservativeRoots.cpp: + (JSC::ConservativeRoots::ConservativeRoots): + (JSC::ConservativeRoots::genericAddPointer): + (JSC::ConservativeRoots::add): + * heap/ConservativeRoots.h: + * heap/Heap.cpp: + (JSC::Heap::Heap): + (JSC::Heap::blockFreeingThreadMain): + (JSC::Heap::reportExtraMemoryCostSlowCase): + (JSC::Heap::getConservativeRegisterRoots): + (JSC::Heap::markRoots): + (JSC::Heap::collect): + (JSC::Heap::releaseFreeBlocks): + * heap/Heap.h: + (JSC::Heap::waterMark): + (JSC::Heap::highWaterMark): + (JSC::Heap::setHighWaterMark): + (JSC::Heap::tryAllocateStorage): + (JSC::Heap::tryReallocateStorage): + * heap/HeapBlock.h: Added. + (JSC::HeapBlock::HeapBlock): + * heap/MarkStack.cpp: + (JSC::MarkStackThreadSharedData::MarkStackThreadSharedData): + (JSC::SlotVisitor::drain): + (JSC::SlotVisitor::drainFromShared): + (JSC::SlotVisitor::startCopying): + (JSC::SlotVisitor::allocateNewSpace): + (JSC::SlotVisitor::copy): + (JSC::SlotVisitor::copyAndAppend): + (JSC::SlotVisitor::doneCopying): + * heap/MarkStack.h: + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::recycle): + (JSC::MarkedBlock::MarkedBlock): + * heap/MarkedBlock.h: + * heap/MarkedSpace.cpp: + (JSC::MarkedSpace::MarkedSpace): + * heap/MarkedSpace.h: + (JSC::MarkedSpace::allocate): + (JSC::MarkedSpace::forEachBlock): + (JSC::MarkedSpace::SizeClass::resetAllocator): + * heap/SlotVisitor.h: + (JSC::SlotVisitor::SlotVisitor): + * heap/TinyBloomFilter.h: + (JSC::TinyBloomFilter::reset): + * runtime/JSArray.cpp: + (JSC::JSArray::JSArray): + (JSC::JSArray::finishCreation): + (JSC::JSArray::tryFinishCreationUninitialized): + (JSC::JSArray::~JSArray): + (JSC::JSArray::enterSparseMode): + (JSC::JSArray::defineOwnNumericProperty): + (JSC::JSArray::setLengthWritable): + (JSC::JSArray::getOwnPropertySlotByIndex): + (JSC::JSArray::getOwnPropertyDescriptor): + (JSC::JSArray::putByIndexBeyondVectorLength): + (JSC::JSArray::deletePropertyByIndex): + (JSC::JSArray::getOwnPropertyNames): + (JSC::JSArray::increaseVectorLength): + (JSC::JSArray::unshiftCountSlowCase): + (JSC::JSArray::setLength): + (JSC::JSArray::pop): + (JSC::JSArray::unshiftCount): + (JSC::JSArray::visitChildren): + (JSC::JSArray::sortNumeric): + (JSC::JSArray::sort): + (JSC::JSArray::compactForSorting): + (JSC::JSArray::subclassData): + (JSC::JSArray::setSubclassData): + (JSC::JSArray::checkConsistency): + * runtime/JSArray.h: + (JSC::JSArray::inSparseMode): + (JSC::JSArray::isLengthWritable): + * wtf/CheckedBoolean.h: Added. + (CheckedBoolean::CheckedBoolean): + (CheckedBoolean::~CheckedBoolean): + (CheckedBoolean::operator bool): + * wtf/DoublyLinkedList.h: + (WTF::::push): + * wtf/StdLibExtras.h: + (WTF::isPointerAligned): + +2012-01-19 Joi Sigurdsson <joi@chromium.org> + + Enable use of precompiled headers in Chromium port on Windows. + + Bug 76381 - Use precompiled headers in Chromium port on Windows + https://bugs.webkit.org/show_bug.cgi?id=76381 + + Reviewed by Tony Chang. + + * JavaScriptCore.gyp/JavaScriptCore.gyp: Include WinPrecompile.gypi. + +2012-01-18 Roland Takacs <takacs.roland@stud.u-szeged.hu> + + Cross-platform processor core counter fix + https://bugs.webkit.org/show_bug.cgi?id=76540 + + Reviewed by Zoltan Herczeg. + + I attached "OS(FREEBSD)" to "#if OS(DARWIN) || OS(OPENBSD) || OS(NETBSD)" + and I removed the OS checking macros from ParallelJobsGeneric.cpp because + the NumberOfCores.cpp contains them for counting CPU cores. + The processor core counter patch located at + https://bugs.webkit.org/show_bug.cgi?id=76530 + + * wtf/NumberOfCores.cpp: + * wtf/ParallelJobsGeneric.cpp: + +2012-01-18 Csaba Osztrogonác <ossy@webkit.org> + + Cross-platform processor core counter + https://bugs.webkit.org/show_bug.cgi?id=76530 + + Unreviewed cross-MinGW buildfix after r105270. + + * wtf/NumberOfCores.cpp: Use windows.h instead of Windows.h. + +2012-01-18 Roland Takacs <takacs.roland@stud.u-szeged.hu> + + Cross-platform processor core counter + https://bugs.webkit.org/show_bug.cgi?id=76530 + + Reviewed by Zoltan Herczeg. + + Two files have been created that include the processor core counter function. + It used to be in ParallelJobsGeneric.h/cpp before. + + * GNUmakefile.list.am: + * JavaScriptCore.gypi: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/Options.cpp: + (JSC::Options::initializeOptions): + * wtf/CMakeLists.txt: + * wtf/NumberOfCores.cpp: Added. + (WTF::numberOfProcessorCores): + * wtf/NumberOfCores.h: Added. + * wtf/ParallelJobsGeneric.cpp: + (WTF::ParallelEnvironment::ParallelEnvironment): + * wtf/ParallelJobsGeneric.h: + +2012-01-18 Balazs Kelemen <kbalazs@webkit.org> + + [Qt] Consolidate layout test crash logging + https://bugs.webkit.org/show_bug.cgi?id=75088 + + Reviewed by Simon Hausmann. + + Move backtrace generating logic into WTFReportBacktrace + and add a way to deinstall signal handlers if we know + that we have already printed the backtrace. + + * JavaScriptCore.exp: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * wtf/Assertions.cpp: + (WTFLogLocker::WTFReportBacktrace): + (WTFLogLocker::WTFSetCrashHook): + (WTFLogLocker::WTFInvokeCrashHook): + * wtf/Assertions.h: + +2012-01-17 Geoffrey Garen <ggaren@apple.com> + + Factored out some code into a helper function. + + I think this might help getting rid of omit-frame-pointer. + + Reviewed by Sam Weinig. + + No benchmark change. + + * runtime/StringPrototype.cpp: + (JSC::removeUsingRegExpSearch): Moved to here... + (JSC::replaceUsingRegExpSearch): ...from here. + +2012-01-17 Caio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org> + + Uint8ClampedArray support + https://bugs.webkit.org/show_bug.cgi?id=74455 + + Reviewed by Filip Pizlo. + + * GNUmakefile.list.am: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/PredictedType.cpp: + (JSC::predictionToString): + (JSC::predictionFromClassInfo): + * bytecode/PredictedType.h: + (JSC::isUint8ClampedArrayPrediction): + (JSC::isActionableMutableArrayPrediction): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::initialize): + (JSC::DFG::AbstractState::execute): + * dfg/DFGNode.h: + (JSC::DFG::Node::shouldSpeculateUint8ClampedArray): + * dfg/DFGPropagator.cpp: + (JSC::DFG::Propagator::propagateNodePredictions): + (JSC::DFG::Propagator::fixupNode): + (JSC::DFG::Propagator::performNodeCSE): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::checkArgumentTypes): + (JSC::DFG::clampDoubleToByte): + (JSC::DFG::compileClampIntegerToByte): + (JSC::DFG::SpeculativeJIT::compilePutByValForByteArray): + (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray): + (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * runtime/JSCell.h: + * runtime/JSGlobalData.h: + * wtf/Forward.h: + * wtf/Uint8Array.h: + * wtf/Uint8ClampedArray.h: Added. + (WTF::Uint8ClampedArray::set): + (WTF::Uint8ClampedArray::create): + (WTF::Uint8ClampedArray::Uint8ClampedArray): + (WTF::Uint8ClampedArray::subarray): + +2012-01-17 Sam Weinig <sam@webkit.org> + + Add helper macro for forward declaring objective-c classes + https://bugs.webkit.org/show_bug.cgi?id=76485 + + Reviewed by Anders Carlsson. + + * wtf/Compiler.h: + Add OBJC_CLASS macro which helps reduce code when forward declaring an + objective-c class in a header which can be included from both Objective-C + and non-Objective-C files. + +2012-01-17 Filip Pizlo <fpizlo@apple.com> + + DFG should be able to do JS and custom getter caching + https://bugs.webkit.org/show_bug.cgi?id=76361 + + Reviewed by Csaba Osztrogonác. + + Fix for 32-bit. + + * dfg/DFGRepatch.cpp: + (JSC::DFG::tryBuildGetByIDList): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2012-01-15 Filip Pizlo <fpizlo@apple.com> + + DFG should be able to do JS and custom getter caching + https://bugs.webkit.org/show_bug.cgi?id=76361 + <rdar://problem/10698060> + + Reviewed by Geoff Garen. + + Added the ability to cache JS getter calls and custom getter calls in the DFG. + Most of this is pretty mundane, since the old JIT supported this functionality + as well. But a couple interesting things had to happen: + + - There are now two variants of GetById: GetById, which works as before, and + GetByIdFlush, which flushes registers prior to doing the GetById. Only + GetByIdFlush can be used for caching getters. We detect which GetById style + to use by looking at the inline caches of the old JIT. + + - Exception handling for getter calls planted in stubs uses a separate lookup + handler routine, which uses the CodeOrigin stored in the StructureStubInfo. + + This is a 40% speed-up in the Dromaeo DOM Traversal average. It removes all of + the DFG regressions we saw in Dromaeo. This is neutral on SunSpider, V8, and + Kraken. + + * bytecode/StructureStubInfo.h: + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGAssemblyHelpers.h: + (JSC::DFG::AssemblyHelpers::emitExceptionCheck): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::willNeedFlush): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCCallHelpers.h: + (JSC::DFG::CCallHelpers::setupResults): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * dfg/DFGJITCompiler.h: + (JSC::DFG::PropertyAccessRecord::PropertyAccessRecord): + (JSC::DFG::JITCompiler::addExceptionCheck): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasIdentifier): + (JSC::DFG::Node::hasHeapPrediction): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPropagator.cpp: + (JSC::DFG::Propagator::propagateNodePredictions): + * dfg/DFGRepatch.cpp: + (JSC::DFG::tryCacheGetByID): + (JSC::DFG::tryBuildGetByIDList): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::appendCallWithExceptionCheckSetResult): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::cachedGetById): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::cachedGetById): + (JSC::DFG::SpeculativeJIT::compile): + +2012-01-16 Jon Lee <jonlee@apple.com> + + Build fix for r105086. + + * Configurations/FeatureDefines.xcconfig: + * wtf/Platform.h: + +2012-01-16 Jon Lee <jonlee@apple.com> + + Remove HTML notifications support on Mac + https://bugs.webkit.org/show_bug.cgi?id=76401 + <rdar://problem/10589881> + + Reviewed by Sam Weinig. + + * wtf/Platform.h: Define ENABLE_HTML_NOTIFICATIONS macro. + +2012-01-16 Zeno Albisser <zeno@webkit.org> + + [Qt] Fix QT_VERSION related warnings when building on Mac OS X + https://bugs.webkit.org/show_bug.cgi?id=76340 + + This bug was caused by r104826. + As already mentioned for https://bugs.webkit.org/show_bug.cgi?id=57239 + we should not use "using namespace WebCore" in header files, + because it might cause ambiguous references. + This patch reverts the changes from r104826 and r104981 + and removes the "using namespace WebCore" statement from + two header files. + + Reviewed by Tor Arne Vestbø. + + * wtf/Platform.h: + +2012-01-16 Carlos Garcia Campos <cgarcia@igalia.com> + + Unreviewed. Fix make distcheck. + + * GNUmakefile.list.am: Fix typo. + +2012-01-16 Pavel Heimlich <tropikhajma@gmail.com> + + Solaris Studio supports alignment macros too + https://bugs.webkit.org/show_bug.cgi?id=75453 + + Reviewed by Hajime Morita. + + * wtf/Alignment.h: + +2012-01-16 Yuqiang Xian <yuqiang.xian@intel.com> + + Build fix on 32bit if verbose debug is enabled in DFG + https://bugs.webkit.org/show_bug.cgi?id=76351 + + Reviewed by Hajime Morita. + + Mostly change "%lu" to "%zu" to print a "size_t" variable. + + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::endBasicBlock): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::parseCodeBlock): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::predictArgumentTypes): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * dfg/DFGOSREntry.cpp: + (JSC::DFG::prepareOSREntry): + +2012-01-15 Filip Pizlo <fpizlo@apple.com> + + The C calling convention logic in DFG::SpeculativeJIT should be available even + when not generating code for the DFG speculative path + https://bugs.webkit.org/show_bug.cgi?id=76355 + + Reviewed by Dan Bernstein. + + Moved all of the logic for placing C call arguments into the right place (stack + or registers) into a new class, DFG::CCallHelpers. This class inherits from + AssemblyHelpers, another DFG grab-bag of helper functions. I could have moved + this code into AssemblyHelpers, but decided against it, because I wanted to + limit the number of methods each class in the JIT has. Hence now we have a + slightly odd organization of JIT classes in DFG: MacroAssembler (basic instruction + emission) <= AssemblyHelpers (some additional JS smarts) <= CCallHelpers + (understands calls to C functions) <= JITCompiler (can compile a graph to machine + code). Each of these except for JITCompiler can be reused for stub compilation. + + * GNUmakefile.list.am: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGCCallHelpers.h: Added. + (JSC::DFG::CCallHelpers::CCallHelpers): + (JSC::DFG::CCallHelpers::resetCallArguments): + (JSC::DFG::CCallHelpers::addCallArgument): + (JSC::DFG::CCallHelpers::setupArguments): + (JSC::DFG::CCallHelpers::setupArgumentsExecState): + (JSC::DFG::CCallHelpers::setupArgumentsWithExecState): + (JSC::DFG::CCallHelpers::setupTwoStubArgs): + (JSC::DFG::CCallHelpers::setupStubArguments): + * dfg/DFGJITCompiler.h: + (JSC::DFG::JITCompiler::JITCompiler): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + +2012-01-15 Pablo Flouret <pablof@motorola.com> + + Fix compilation errors on build-webkit --debug --no-video on mac. + https://bugs.webkit.org/show_bug.cgi?id=75867 + + Reviewed by Philippe Normand. + + Make ENABLE_VIDEO_TRACK conditional on ENABLE_VIDEO, video track feature + doesn't build without video. + + * wtf/Platform.h: + +2012-01-14 David Levin <levin@chromium.org> + + HWndDC should be in platform/win instead of wtf. + https://bugs.webkit.org/show_bug.cgi?id=76314 + + Reviewed by Sam Weinig. + + * JavaScriptCore.gyp/JavaScriptCore.gyp: + * JavaScriptCore.gypi: + +2012-01-13 David Levin <levin@chromium.org> + + check-webkit-style: should encourage the use of Own* classes for Windows DC. + https://bugs.webkit.org/show_bug.cgi?id=76227 + + Reviewed by Dirk Pranke. + + * wtf/win/HWndDCWin.h: + (WTF::HwndDC::HwndDC): Add a way to do GetDCEx. + There are no users, but I want to catch this in check-webkit-style + and tell any users to use HwndDC to avoid leaks. + +2012-01-13 David Levin <levin@chromium.org> + + Header file is missing header guard. + + Reviewed by Dirk Pranke. + + * wtf/win/HWndDCWin.h: Added the guards. + +2012-01-13 Andy Wingo <wingo@igalia.com> + + Eval in strict mode does not need dynamic checks + https://bugs.webkit.org/show_bug.cgi?id=76286 + + Reviewed by Oliver Hunt. + + * runtime/JSActivation.cpp (JSC::JSActivation::JSActivation): + Eval in strict mode cannot introduce variables, so it not impose + the need for dynamic checks. + +2012-01-13 David Levin <levin@chromium.org> + + HWndDC is a better name than HwndDC. + https://bugs.webkit.org/show_bug.cgi?id=76281 + + Reviewed by Darin Adler. + + * JavaScriptCore.gyp/JavaScriptCore.gyp: + * JavaScriptCore.gypi: + * wtf/win/HWndDCWin.h: Renamed from Source/JavaScriptCore/wtf/win/HwndDCWin.h. + (WTF::HWndDC::HWndDC): + (WTF::HWndDC::~HWndDC): + (WTF::HWndDC::operator HDC): + +2012-01-13 YoungTaeck Song <youngtaeck.song@samsung.com> + + [EFL] Add OwnPtr specialization for Eina_Module. + https://bugs.webkit.org/show_bug.cgi?id=76255 + + Reviewed by Andreas Kling. + + Add an overload for deleteOwnedPtr(Eina_Module*) on EFL port. + + * wtf/OwnPtrCommon.h: + * wtf/efl/OwnPtrEfl.cpp: + (WTF::deleteOwnedPtr): + +2012-01-13 Yuqiang Xian <yuqiang.xian@intel.com> + + Unreviewed build fix after r104787 if JIT_VERBOSE_OSR is defined + + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + +2012-01-12 Hajime Morrita <morrita@chromium.org> + + JavaScriptCore: Mark all exported symbols in the header file automatically. + https://bugs.webkit.org/show_bug.cgi?id=72855 + + Reviewed by Darin Adler. + + Added WTF_EXPORT_PRIVATE and JS_EXPORT_PRIVATE based on JavaScriptCore.exp files. + The change is generated by a tool calledListExportables (https://github.com/omo/ListExportables) + + * API/OpaqueJSString.h: + * bytecode/CodeBlock.h: + * bytecode/SamplingTool.h: + * debugger/Debugger.h: + * debugger/DebuggerActivation.h: + * debugger/DebuggerCallFrame.h: + * heap/AllocationSpace.h: + * heap/HandleHeap.h: + * heap/Heap.h: + * heap/MachineStackMarker.h: + * heap/MarkStack.h: + * heap/VTableSpectrum.h: + * heap/WriteBarrierSupport.h: + * parser/Nodes.h: + * parser/ParserArena.h: + * profiler/Profile.h: + * runtime/ArgList.h: + * runtime/CallData.h: + * runtime/Completion.h: + * runtime/ConstructData.h: + * runtime/DateInstance.h: + * runtime/Error.h: + * runtime/ExceptionHelpers.h: + * runtime/FunctionConstructor.h: + * runtime/Identifier.h: + * runtime/InitializeThreading.h: + * runtime/InternalFunction.h: + * runtime/JSArray.h: + * runtime/JSByteArray.h: + * runtime/JSCell.h: + * runtime/JSFunction.h: + * runtime/JSGlobalData.cpp: + * runtime/JSGlobalData.h: + * runtime/JSGlobalObject.h: + * runtime/JSGlobalThis.h: + * runtime/JSLock.h: + * runtime/JSObject.h: + * runtime/JSString.h: + * runtime/JSValue.h: + * runtime/JSVariableObject.h: + * runtime/Lookup.h: + * runtime/MemoryStatistics.h: + * runtime/ObjectPrototype.h: + * runtime/Options.h: + * runtime/PropertyDescriptor.h: + * runtime/PropertyNameArray.h: + * runtime/PropertySlot.h: + * runtime/RegExp.h: + * runtime/RegExpObject.h: + * runtime/SamplingCounter.h: + * runtime/SmallStrings.h: + * runtime/StringObject.h: + * runtime/Structure.h: + * runtime/TimeoutChecker.h: + * runtime/UString.h: + * runtime/WriteBarrier.h: + * wtf/ArrayBufferView.h: + * wtf/ByteArray.h: + * wtf/CryptographicallyRandomNumber.h: + * wtf/CurrentTime.h: + * wtf/DateMath.h: + * wtf/DecimalNumber.h: + * wtf/FastMalloc.cpp: + * wtf/FastMalloc.h: + * wtf/MD5.h: + * wtf/MainThread.h: + * wtf/MetaAllocator.h: + * wtf/MetaAllocatorHandle.h: + * wtf/OSAllocator.h: + * wtf/PageBlock.h: + * wtf/RandomNumber.h: + * wtf/RefCountedLeakCounter.h: + * wtf/SHA1.h: + * wtf/Threading.cpp: + * wtf/Threading.h: + * wtf/ThreadingPrimitives.h: + * wtf/WTFThreadData.h: + * wtf/dtoa.h: + * wtf/text/AtomicString.h: + * wtf/text/CString.h: + * wtf/text/StringBuilder.h: + * wtf/text/StringImpl.h: + * wtf/text/WTFString.h: + * wtf/unicode/Collator.h: + * wtf/unicode/UTF8.h: + * yarr/Yarr.h: + * yarr/YarrPattern.h: + +2012-01-12 MORITA Hajime <morrita@google.com> + + [Chromium] JSExportMacros.h should be visible. + https://bugs.webkit.org/show_bug.cgi?id=76147 + + Reviewed by Tony Chang. + + * config.h: + +2012-01-12 David Levin <levin@chromium.org> + + HwndDC is a better name than OwnGetDC. + https://bugs.webkit.org/show_bug.cgi?id=76235 + + Reviewed by Dmitry Titov. + + This is a better name for two reasons: + 1. "Own" implies "delete". In this case, the final call is a release (ReleaseDC). + 2. "Ref" would be a better name due to the release but the RefPtr (and OwnPtr) + classes always take something to hold on to. In this case, the object (the DC) + is created by the class once it is given a Window to ensure that the HDC + was actually created using GetDC. + + * JavaScriptCore.gyp/JavaScriptCore.gyp: + * JavaScriptCore.gypi: + * wtf/win/HwndDCWin.h: Renamed from Source/JavaScriptCore/wtf/win/OwnGetDCWin.h. + (WTF::HwndDC::HwndDC): + (WTF::HwndDC::~HwndDC): + (WTF::HwndDC::operator HDC): + +2012-01-12 Gavin Barraclough <barraclough@apple.com> + + Clean up putDirect (part 2) + https://bugs.webkit.org/show_bug.cgi?id=76232 + + Reviewed by Sam Weinig. + + Rename putWithAttributes to putDirectVirtual, to identify that this + has the same unchecked-DefineOwnProperty behaviour, change putDirectInternal + to be templated on an enum indicating which behaviour it is supposed to be + implementing, and change clients that are defining properties to call + putDirectInternal correctly. + + * API/JSObjectRef.cpp: + (JSObjectSetProperty): + * JavaScriptCore.exp: + * debugger/DebuggerActivation.cpp: + (JSC::DebuggerActivation::putDirectVirtual): + * debugger/DebuggerActivation.h: + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * runtime/ClassInfo.h: + * runtime/Error.cpp: + (JSC::addErrorInfo): + * runtime/JSActivation.cpp: + (JSC::JSActivation::putDirectVirtual): + * runtime/JSActivation.h: + * runtime/JSCell.cpp: + (JSC::JSCell::putDirectVirtual): + * runtime/JSCell.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::putDirectVirtual): + * runtime/JSGlobalObject.h: + * runtime/JSObject.cpp: + (JSC::JSObject::put): + (JSC::JSObject::putDirectVirtual): + (JSC::JSObject::defineGetter): + (JSC::JSObject::initializeGetterSetterProperty): + (JSC::JSObject::defineSetter): + (JSC::putDescriptor): + * runtime/JSObject.h: + (JSC::JSObject::putDirectInternal): + (JSC::JSObject::putOwnDataProperty): + (JSC::JSObject::putDirect): + * runtime/JSStaticScopeObject.cpp: + (JSC::JSStaticScopeObject::putDirectVirtual): + * runtime/JSStaticScopeObject.h: + * runtime/JSVariableObject.cpp: + (JSC::JSVariableObject::putDirectVirtual): + * runtime/JSVariableObject.h: + +2012-01-12 Gavin Barraclough <barraclough@apple.com> + + Clean up putDirect (part 1) + https://bugs.webkit.org/show_bug.cgi?id=76232 + + Reviewed by Sam Weinig. + + putDirect has ambiguous semantics, clean these up a bit. + + putDirect generally behaves a bit like a fast defineOwnProperty, but one that + always creates the property, with no checking to validate the put it permitted. + + It also encompasses two slightly different behaviors. + (1) a fast form of put for JSActivation, which doesn't have to handle searching + the prototype chain, getter/setter properties, or the magic __proto__ value. + Break this out as a new method, 'putOwnDataProperty'. + (2) the version of putDirect on JSValue will also check for overwriting ReadOnly + values, in strict mode. This is, however, not so smart on a few level, since + it is only called from op_put_by_id with direct set, which is only used with + an object as the base, and is only used to put new properties onto objects. + + * dfg/DFGOperations.cpp: + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * runtime/JSActivation.cpp: + (JSC::JSActivation::put): + * runtime/JSFunction.cpp: + (JSC::JSFunction::getOwnPropertySlot): + * runtime/JSObject.h: + (JSC::JSObject::putOwnDataProperty): + * runtime/JSValue.h: + +2012-01-12 Gavin Barraclough <barraclough@apple.com> + + https://bugs.webkit.org/show_bug.cgi?id=76141 + defineSetter/defineGetter may fail to update Accessor attribute + + Reviewed by Oliver Hunt. + + * runtime/JSObject.cpp: + (JSC::JSObject::defineGetter): + (JSC::JSObject::initializeGetterSetterProperty): + (JSC::JSObject::defineSetter): + * runtime/Structure.cpp: + (JSC::Structure::attributeChangeTransition): + * runtime/Structure.h: + +2012-01-12 David Levin <levin@chromium.org> + + [chromium] Fix DC leak in WebScreenInfoFactory. + https://bugs.webkit.org/show_bug.cgi?id=76203 + + Reviewed by Dmitry Titov. + + * JavaScriptCore.gyp/JavaScriptCore.gyp: Added OwnGetDCWin.h + * JavaScriptCore.gypi: Added OwnGetDCWin.h + * JavaScriptCore/wtf/win/OwnGetDCWin.h: Made an owner class for GetDC which needs ReleaseDC as opposed to DeleteDC. + +2012-01-11 Gavin Barraclough <barraclough@apple.com> + + Allow accessor get/set property to be set to undefined + https://bugs.webkit.org/show_bug.cgi?id=76148 + + Reviewed by Oliver Hunt. + + AccessorDescriptor properties may have their get & set properties defined to reference a function + (Callable object) or be set to undefined. Valid PropertyDescriptors created by toPropertyDescriptor + (defined from JS code via Object.defineProperty, etc) have get and set properties that are in one of + three states (1) nonexistent, (2) set to undefined, or (3) a function (any Callable object). + + On the PropertyDescriptor object these three states are represneted by JSValue(), jsUndefined(), and + any JSObject* (with a constraint that this must be callable). + + Logically the get/set property of an accessor descriptor on an object might be in any of the three + states above, but in practice there is no way to distinguish between the first two states. As such + we stor the get/set values in property storage in a JSObject* field, with 0 indicating absent or + undefined. When unboxing to a PropertyDescriptor, map this back to a JS undefined value. + + * runtime/GetterSetter.h: + (JSC::GetterSetter::setGetter): + (JSC::GetterSetter::setSetter): + - Allow the getter/setter to be cleared. + * runtime/JSArray.cpp: + (JSC::JSArray::putDescriptor): + - Changed to call getterObject/setterObject. + (JSC::JSArray::defineOwnNumericProperty): + - Added ASSERT. + * runtime/JSObject.cpp: + (JSC::putDescriptor): + (JSC::JSObject::defineOwnProperty): + - Changed to call getterObject/setterObject. + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorGetOwnPropertyDescriptor): + - getter/setter values read from properties on object are never missing, they will now be set as undefined by 'setDescriptor'. + (JSC::toPropertyDescriptor): + - Do not translate undefined->empty, this loses an important distinction between a get/set property being absent, or being explicitly set to undefined. + * runtime/PropertyDescriptor.cpp: + (JSC::PropertyDescriptor::getterObject): + (JSC::PropertyDescriptor::setterObject): + - Accessors to convert the get/set property to an object pointer, converting undefined to 0. + (JSC::PropertyDescriptor::setDescriptor): + (JSC::PropertyDescriptor::setAccessorDescriptor): + - Translate a getter/setter internally represented at 0 to undefined, indicating that it is present. + * runtime/PropertyDescriptor.h: + - Declare getterObject/setterObject. + +2012-01-12 Zeno Albisser <zeno@webkit.org> + + [Qt][WK2][Mac] Conflict of MacTypes.h defining a Fixed type after r104560. + https://bugs.webkit.org/show_bug.cgi?id=76175 + + Defining ENABLE_CSS_FILTERS leads to ambiguous references + due to MacTypes.h being included. + Defining CF_OPEN_SOURCE works around this problem. + + Reviewed by Simon Hausmann. + + * wtf/Platform.h: + +2012-01-12 Simon Hausmann <simon.hausmann@nokia.com> + + Make the new WTF module build on Qt + https://bugs.webkit.org/show_bug.cgi?id=76163 + + Reviewed by Tor Arne Vestbø. + + * JavaScriptCore.pro: Removed wtf from the subdirs to build. + +2012-01-11 Filip Pizlo <fpizlo@apple.com> + + CodeBlock::m_executeCounter should be renamed to CodeBlock::m_jitExecuteCounter + https://bugs.webkit.org/show_bug.cgi?id=76144 + <rdar://problem/10681711> + + Rubber stamped by Gavin Barraclough. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::addressOfJITExecuteCounter): + (JSC::CodeBlock::offsetOfJITExecuteCounter): + (JSC::CodeBlock::jitExecuteCounter): + (JSC::CodeBlock::optimizeNextInvocation): + (JSC::CodeBlock::dontOptimizeAnytimeSoon): + (JSC::CodeBlock::optimizeAfterWarmUp): + (JSC::CodeBlock::optimizeAfterLongWarmUp): + (JSC::CodeBlock::optimizeSoon): + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * jit/JIT.cpp: + (JSC::JIT::emitOptimizationCheck): + +2012-01-11 Gavin Barraclough <barraclough@apple.com> + + Merge 'Getter'/'Setter' attributes into 'Accessor' + https://bugs.webkit.org/show_bug.cgi?id=76141 + + Reviewed by Filip Pizlo. + + These are currently ambiguous (and used inconsistently). It would logically appear + that either being bit set implies that the corresponding type of accessor is present + but (a) we don't correctly enforce this, and (b) this means the attributes would not + be able to distinguish between a data descriptor and an accessor descriptor with + neither a getter nor setter defined (which is a descriptor permissible under the spec). + This ambiguity would lead to unsafe property caching behavior (though this does not + represent an actual current bug, since we are currently unable to create descriptors + that have neither a getter nor setter, it just prevents us from doing so). + + * runtime/Arguments.cpp: + (JSC::Arguments::createStrictModeCallerIfNecessary): + (JSC::Arguments::createStrictModeCalleeIfNecessary): + * runtime/JSArray.cpp: + (JSC::SparseArrayValueMap::put): + (JSC::JSArray::putDescriptor): + * runtime/JSBoundFunction.cpp: + (JSC::JSBoundFunction::finishCreation): + * runtime/JSFunction.cpp: + (JSC::JSFunction::getOwnPropertySlot): + (JSC::JSFunction::getOwnPropertyDescriptor): + * runtime/JSObject.cpp: + (JSC::JSObject::defineGetter): + (JSC::JSObject::initializeGetterSetterProperty): + (JSC::JSObject::defineSetter): + (JSC::putDescriptor): + (JSC::JSObject::defineOwnProperty): + * runtime/JSObject.h: + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorDefineProperty): + * runtime/PropertyDescriptor.cpp: + (JSC::PropertyDescriptor::setDescriptor): + (JSC::PropertyDescriptor::setAccessorDescriptor): + (JSC::PropertyDescriptor::setSetter): + (JSC::PropertyDescriptor::setGetter): + (JSC::PropertyDescriptor::attributesOverridingCurrent): + +2012-01-11 Gavin Barraclough <barraclough@apple.com> + + Object.defineProperty([], 'length', {}) should not make length read-only + https://bugs.webkit.org/show_bug.cgi?id=76097 + + Reviewed by Oliver Hunt. + + * runtime/JSArray.cpp: + (JSC::JSArray::defineOwnProperty): + - We should be checking writablePresent(). + +2012-01-11 Filip Pizlo <fpizlo@apple.com> + + Code duplication for invoking the JIT and DFG should be reduced + https://bugs.webkit.org/show_bug.cgi?id=76117 + <rdar://problem/10680189> + + Rubber stamped by Geoff Garen. + + * GNUmakefile.list.am: + * JavaScriptCore.xcodeproj/project.pbxproj: + * jit/JITDriver.h: Added. + (JSC::jitCompileIfAppropriate): + (JSC::jitCompileFunctionIfAppropriate): + * runtime/Executable.cpp: + (JSC::EvalExecutable::compileInternal): + (JSC::ProgramExecutable::compileInternal): + (JSC::FunctionExecutable::compileForCallInternal): + (JSC::FunctionExecutable::compileForConstructInternal): + +2012-01-11 Geoffrey Garen <ggaren@apple.com> + + Bytecode dumping is broken for call opcodes (due to two new operands) + https://bugs.webkit.org/show_bug.cgi?id=75886 + + Reviewed by Oliver Hunt. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printCallOp): Made a helper function, so I wouldn't have + to fix this more than once. The helper function skips the extra two operands + at the end of the opcode, used for optimization. + + (JSC::CodeBlock::dump): Used the helper function. + + * bytecode/CodeBlock.h: Declared the helper function. + +2012-01-09 Geoffrey Garen <ggaren@apple.com> + + REGRESSION: d3 Bullet Charts demo doesn't work (call with argument assignment is broken) + https://bugs.webkit.org/show_bug.cgi?id=75911 + + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::emitNodeForLeftHandSide): Cleanup: No need to + explicitly cast to our return type in C++. + + * bytecompiler/NodesCodegen.cpp: + (JSC::FunctionCallResolveNode::emitBytecode): + (JSC::ApplyFunctionCallDotNode::emitBytecode): Make sure to copy our function + into a temporary register before evaluating our arguments, since argument + evaluation might include function calls or assignments that overwrite our callee by name. + +2012-01-11 Michael Saboff <msaboff@apple.com> + + v8-regexp spends 35% of its time allocating and copying internal regexp results data + https://bugs.webkit.org/show_bug.cgi?id=76079 + + Reviewed by Geoffrey Garen. + + Added a new RegExpResults struct that has the input string, the number of + subexpressions and the output vector. Changed RegExpConstructor to + include a RegExpConstructorPrivate instead of having a reference to one. + Changed RegExpMatchesArray to include a RegExpResults instead of a + reference to a RegExpConstructorPrivate. Created an overloaded assignment + operator to assign a RegExpConstructorPrivate to a RegExpResults. + Collectively this change is worth 24% performance improvement to v8-regexp. + + * runtime/RegExpConstructor.cpp: + (JSC::RegExpResult::operator=): + (JSC::RegExpConstructor::RegExpConstructor): + (JSC::RegExpMatchesArray::RegExpMatchesArray): + (JSC::RegExpMatchesArray::finishCreation): + (JSC::RegExpMatchesArray::~RegExpMatchesArray): + (JSC::RegExpMatchesArray::fillArrayInstance): + (JSC::RegExpConstructor::arrayOfMatches): + (JSC::RegExpConstructor::getBackref): + (JSC::RegExpConstructor::getLastParen): + (JSC::RegExpConstructor::getLeftContext): + (JSC::RegExpConstructor::getRightContext): + (JSC::RegExpConstructor::setInput): + (JSC::RegExpConstructor::input): + (JSC::RegExpConstructor::setMultiline): + (JSC::RegExpConstructor::multiline): + * runtime/RegExpConstructor.h: + (JSC::RegExpResult::RegExpResult): + (JSC::RegExpConstructor::performMatch): + * runtime/RegExpMatchesArray.h: + (JSC::RegExpMatchesArray::create): + (JSC::RegExpMatchesArray::getOwnPropertySlot): + (JSC::RegExpMatchesArray::getOwnPropertySlotByIndex): + (JSC::RegExpMatchesArray::getOwnPropertyDescriptor): + (JSC::RegExpMatchesArray::put): + (JSC::RegExpMatchesArray::putByIndex): + (JSC::RegExpMatchesArray::deleteProperty): + (JSC::RegExpMatchesArray::deletePropertyByIndex): + (JSC::RegExpMatchesArray::getOwnPropertyNames): + +2012-01-11 Eugene Girard <girard@google.com> + + Typo in error message: Unexpected token 'defualt' + https://bugs.webkit.org/show_bug.cgi?id=75105 + + Reviewed by Simon Fraser. + + * parser/Parser.h: + (JSC::Parser::getTokenName): + +2012-01-11 Anders Carlsson <andersca@apple.com> + + Assertion failure in JSC::allocateCell trying to allocate a JSString + https://bugs.webkit.org/show_bug.cgi?id=76101 + + Reviewed by Adam Roben. + + Remove the ExecutableBase::s_info and JSString::s_info static member variables from the .def file and + export them explicitly using the JS_EXPORTDATA macro. + + member variables explicitly using + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * runtime/Executable.h: + * runtime/JSString.h: + 2012-01-10 Mark Rowe <mrowe@apple.com> <rdar://problem/10673792> jsc should install directly in to versioned Resources subfolder diff --git a/Source/JavaScriptCore/Configurations/Base.xcconfig b/Source/JavaScriptCore/Configurations/Base.xcconfig index ba5c75e29..e304bd1fb 100644 --- a/Source/JavaScriptCore/Configurations/Base.xcconfig +++ b/Source/JavaScriptCore/Configurations/Base.xcconfig @@ -82,12 +82,19 @@ REAL_PLATFORM_NAME_macosx = macosx; TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR); +NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR = $(NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR_$(REAL_PLATFORM_NAME)); +NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR_iphoneos = $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks; +NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR_iphonesimulator = $(NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR_iphoneos); +NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx = $(SYSTEM_LIBRARY_DIR)/Frameworks; JAVASCRIPTCORE_FRAMEWORKS_DIR = $(JAVASCRIPTCORE_FRAMEWORKS_DIR_$(REAL_PLATFORM_NAME)); -JAVASCRIPTCORE_FRAMEWORKS_DIR_iphoneos = $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks; +JAVASCRIPTCORE_FRAMEWORKS_DIR_iphoneos = $(NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR_iphoneos); JAVASCRIPTCORE_FRAMEWORKS_DIR_iphonesimulator = $(JAVASCRIPTCORE_FRAMEWORKS_DIR_iphoneos); -JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx = $(SYSTEM_LIBRARY_DIR)/Frameworks; +JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx = $(JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx_USE_STAGING_INSTALL_PATH_$(USE_STAGING_INSTALL_PATH)); +JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx_USE_STAGING_INSTALL_PATH_ = $(JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx_USE_STAGING_INSTALL_PATH_NO); +JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx_USE_STAGING_INSTALL_PATH_NO = $(NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR); +JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx_USE_STAGING_INSTALL_PATH_YES = $(SYSTEM_LIBRARY_DIR)/StagedFrameworks/Safari; // DEBUG_DEFINES, GCC_OPTIMIZATION_LEVEL, STRIP_INSTALLED_PRODUCT and DEAD_CODE_STRIPPING vary between the debug and normal variants. // We set up the values for each variant here, and have the Debug configuration in the Xcode project use the _debug variant. diff --git a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig index ac37615e8..3846b27bf 100644 --- a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig +++ b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig @@ -106,11 +106,13 @@ ENABLE_PROGRESS_TAG = ENABLE_PROGRESS_TAG; ENABLE_QUOTA = ; ENABLE_REGISTER_PROTOCOL_HANDLER = ; ENABLE_REQUEST_ANIMATION_FRAME = ENABLE_REQUEST_ANIMATION_FRAME; +ENABLE_SHADOW_DOM = ; ENABLE_SHARED_WORKERS = ENABLE_SHARED_WORKERS; ENABLE_SQL_DATABASE = ENABLE_SQL_DATABASE; ENABLE_STYLE_SCOPED = ; ENABLE_SVG = ENABLE_SVG; ENABLE_SVG_FONTS = ENABLE_SVG_FONTS; +ENABLE_TEXT_NOTIFICATIONS_ONLY = ENABLE_TEXT_NOTIFICATIONS_ONLY; ENABLE_TOUCH_ICON_LOADING = ; ENABLE_VIDEO = ENABLE_VIDEO; ENABLE_VIDEO_TRACK = ; @@ -121,4 +123,4 @@ ENABLE_WEB_TIMING = ; ENABLE_WORKERS = ENABLE_WORKERS; ENABLE_XSLT = ENABLE_XSLT; -FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CLIENT_BASED_GEOLOCATION) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_GRID_LAYOUT) $(ENABLE_CSS_SHADERS) $(ENABLE_DATALIST) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_ICONDATABASE) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_COLOR) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LINK_PREFETCH) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_TAG) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_TAG) $(ENABLE_QUOTA) $(ENABLE_REGISTER_PROTOCOL_HANDLER) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WORKERS) $(ENABLE_XSLT); +FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CLIENT_BASED_GEOLOCATION) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_GRID_LAYOUT) $(ENABLE_CSS_SHADERS) $(ENABLE_DATALIST) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_ICONDATABASE) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_COLOR) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LINK_PREFETCH) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_TAG) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_TAG) $(ENABLE_QUOTA) $(ENABLE_REGISTER_PROTOCOL_HANDLER) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WORKERS) $(ENABLE_XSLT); diff --git a/Source/JavaScriptCore/Configurations/JavaScriptCore.xcconfig b/Source/JavaScriptCore/Configurations/JavaScriptCore.xcconfig index e6b5b4d2a..827749871 100644 --- a/Source/JavaScriptCore/Configurations/JavaScriptCore.xcconfig +++ b/Source/JavaScriptCore/Configurations/JavaScriptCore.xcconfig @@ -46,8 +46,5 @@ GCC_PREFIX_HEADER = JavaScriptCorePrefix.h; HEADER_SEARCH_PATHS = "${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore" $(HEADER_SEARCH_PATHS); INFOPLIST_FILE = Info.plist; INSTALL_PATH = $(JAVASCRIPTCORE_FRAMEWORKS_DIR); +DYLIB_INSTALL_NAME_BASE = $(NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR); PRODUCT_NAME = JavaScriptCore; - -OTHER_CFLAGS = $(OTHER_CFLAGS_$(CONFIGURATION)_$(CURRENT_VARIANT)); -OTHER_CFLAGS_Release_normal = -fomit-frame-pointer -funwind-tables; -OTHER_CFLAGS_Production_normal = $(OTHER_CFLAGS_Release_normal); diff --git a/Source/JavaScriptCore/Configurations/Version.xcconfig b/Source/JavaScriptCore/Configurations/Version.xcconfig index 33019e72f..0510654ff 100644 --- a/Source/JavaScriptCore/Configurations/Version.xcconfig +++ b/Source/JavaScriptCore/Configurations/Version.xcconfig @@ -22,7 +22,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. MAJOR_VERSION = 535; -MINOR_VERSION = 16; +MINOR_VERSION = 19; TINY_VERSION = 0; FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION); diff --git a/Source/JavaScriptCore/GNUmakefile.am b/Source/JavaScriptCore/GNUmakefile.am index 8498702dc..654cd108e 100644 --- a/Source/JavaScriptCore/GNUmakefile.am +++ b/Source/JavaScriptCore/GNUmakefile.am @@ -60,6 +60,7 @@ javascriptcore_cppflags += \ -I$(srcdir)/Source/JavaScriptCore/parser \ -I$(srcdir)/Source/JavaScriptCore/profiler \ -I$(srcdir)/Source/JavaScriptCore/runtime \ + -I$(srcdir)/Source/JavaScriptCore/tools \ -I$(srcdir)/Source/JavaScriptCore/wtf \ -I$(srcdir)/Source/JavaScriptCore/wtf \ -I$(srcdir)/Source/JavaScriptCore/wtf/gobject \ diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index 4fb218199..de5338dd4 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -83,6 +83,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/assembler/X86Assembler.h \ Source/JavaScriptCore/bytecode/CallLinkInfo.cpp \ Source/JavaScriptCore/bytecode/CallLinkInfo.h \ + Source/JavaScriptCore/bytecode/CallLinkStatus.cpp \ + Source/JavaScriptCore/bytecode/CallLinkStatus.h \ Source/JavaScriptCore/bytecode/CallReturnOffsetToBytecodeOffset.h \ Source/JavaScriptCore/bytecode/CodeType.h \ Source/JavaScriptCore/bytecode/CodeBlock.cpp \ @@ -93,21 +95,28 @@ javascriptcore_sources += \ Source/JavaScriptCore/bytecode/DFGExitProfile.h \ Source/JavaScriptCore/bytecode/EvalCodeCache.h \ Source/JavaScriptCore/bytecode/ExpressionRangeInfo.h \ + Source/JavaScriptCore/bytecode/GetByIdStatus.cpp \ + Source/JavaScriptCore/bytecode/GetByIdStatus.h \ Source/JavaScriptCore/bytecode/GlobalResolveInfo.h \ - Source/JavaScriptCore/bytecode/HandelerInfo.h \ + Source/JavaScriptCore/bytecode/HandlerInfo.h \ Source/JavaScriptCore/bytecode/Instruction.h \ Source/JavaScriptCore/bytecode/JumpTable.cpp \ Source/JavaScriptCore/bytecode/JumpTable.h \ Source/JavaScriptCore/bytecode/LineInfo.h \ Source/JavaScriptCore/bytecode/MethodCallLinkInfo.cpp \ Source/JavaScriptCore/bytecode/MethodCallLinkInfo.h \ + Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp \ + Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h \ Source/JavaScriptCore/bytecode/Opcode.cpp \ Source/JavaScriptCore/bytecode/Opcode.h \ Source/JavaScriptCore/bytecode/PredictedType.cpp \ Source/JavaScriptCore/bytecode/PredictedType.h \ Source/JavaScriptCore/bytecode/PredictionTracker.h \ + Source/JavaScriptCore/bytecode/PutByIdStatus.cpp \ + Source/JavaScriptCore/bytecode/PutByIdStatus.h \ Source/JavaScriptCore/bytecode/SamplingTool.cpp \ Source/JavaScriptCore/bytecode/SamplingTool.h \ + Source/JavaScriptCore/bytecode/StructureSet.h \ Source/JavaScriptCore/bytecode/StructureStubInfo.cpp \ Source/JavaScriptCore/bytecode/StructureStubInfo.h \ Source/JavaScriptCore/bytecode/ValueProfile.cpp \ @@ -129,6 +138,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/dfg/DFGByteCodeCache.h \ Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp \ Source/JavaScriptCore/dfg/DFGByteCodeParser.h \ + Source/JavaScriptCore/dfg/DFGCCallHelpers.h \ Source/JavaScriptCore/dfg/DFGCapabilities.cpp \ Source/JavaScriptCore/dfg/DFGCapabilities.h \ Source/JavaScriptCore/dfg/DFGCommon.h \ @@ -165,12 +175,13 @@ javascriptcore_sources += \ Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp \ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp \ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h \ - Source/JavaScriptCore/dfg/DFGStructureSet.h \ Source/JavaScriptCore/dfg/DFGThunks.cpp \ Source/JavaScriptCore/dfg/DFGThunks.h \ Source/JavaScriptCore/dfg/DFGVariableAccessData.h \ - Source/JavaScriptCore/heap/AllocationSpace.cpp \ - Source/JavaScriptCore/heap/AllocationSpace.h \ + Source/JavaScriptCore/heap/BumpBlock.h \ + Source/JavaScriptCore/heap/BumpSpace.cpp \ + Source/JavaScriptCore/heap/BumpSpace.h \ + Source/JavaScriptCore/heap/BumpSpaceInlineMethods.h \ Source/JavaScriptCore/heap/CardSet.h \ Source/JavaScriptCore/heap/ConservativeRoots.cpp \ Source/JavaScriptCore/heap/ConservativeRoots.h \ @@ -179,6 +190,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/heap/Handle.h \ Source/JavaScriptCore/heap/HandleHeap.cpp \ Source/JavaScriptCore/heap/HandleHeap.h \ + Source/JavaScriptCore/heap/HeapBlock.h \ Source/JavaScriptCore/heap/SlotVisitor.h \ Source/JavaScriptCore/heap/HandleStack.cpp \ Source/JavaScriptCore/heap/HandleStack.h \ @@ -250,6 +262,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/icu/unicode/utf_old.h \ Source/JavaScriptCore/icu/unicode/utypes.h \ Source/JavaScriptCore/icu/unicode/uversion.h \ + Source/JavaScriptCore/interpreter/AbstractPC.cpp \ + Source/JavaScriptCore/interpreter/AbstractPC.h \ Source/JavaScriptCore/interpreter/CachedCall.h \ Source/JavaScriptCore/interpreter/CallFrameClosure.h \ Source/JavaScriptCore/interpreter/CallFrame.cpp \ @@ -268,6 +282,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/jit/JITCall32_64.cpp \ Source/JavaScriptCore/jit/JITCall.cpp \ Source/JavaScriptCore/jit/JITCode.h \ + Source/JavaScriptCore/jit/JITDriver.h \ Source/JavaScriptCore/jit/JIT.cpp \ Source/JavaScriptCore/jit/JIT.h \ Source/JavaScriptCore/jit/JITExceptions.cpp \ @@ -510,6 +525,12 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/WeakGCMap.h \ Source/JavaScriptCore/runtime/WeakRandom.h \ Source/JavaScriptCore/runtime/WriteBarrier.h \ + Source/JavaScriptCore/tools/CodeProfile.cpp \ + Source/JavaScriptCore/tools/CodeProfile.h \ + Source/JavaScriptCore/tools/CodeProfiling.cpp \ + Source/JavaScriptCore/tools/CodeProfiling.h \ + Source/JavaScriptCore/tools/ProfileTreeNode.h \ + Source/JavaScriptCore/tools/TieredMMapArray.h \ Source/JavaScriptCore/wtf/Alignment.h \ Source/JavaScriptCore/wtf/AlwaysInline.h \ Source/JavaScriptCore/wtf/ArrayBuffer.cpp \ @@ -531,6 +552,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/wtf/ByteArray.cpp \ Source/JavaScriptCore/wtf/ByteArray.h \ Source/JavaScriptCore/wtf/CheckedArithmetic.h \ + Source/JavaScriptCore/wtf/CheckedBoolean.h \ Source/JavaScriptCore/wtf/Compiler.h \ Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp \ Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.h \ @@ -616,6 +638,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/wtf/NonCopyingSort.h \ Source/JavaScriptCore/wtf/NotFound.h \ Source/JavaScriptCore/wtf/NullPtr.h \ + Source/JavaScriptCore/wtf/NumberOfCores.cpp \ + Source/JavaScriptCore/wtf/NumberOfCores.h \ Source/JavaScriptCore/wtf/OSAllocator.h \ Source/JavaScriptCore/wtf/OSRandomSource.cpp \ Source/JavaScriptCore/wtf/OSRandomSource.h \ @@ -704,6 +728,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/wtf/Uint16Array.h \ Source/JavaScriptCore/wtf/Uint32Array.h \ Source/JavaScriptCore/wtf/Uint8Array.h \ + Source/JavaScriptCore/wtf/Uint8ClampedArray.h \ Source/JavaScriptCore/wtf/unicode/CharacterNames.h \ Source/JavaScriptCore/wtf/unicode/Collator.h \ Source/JavaScriptCore/wtf/unicode/CollatorDefault.cpp \ diff --git a/Source/JavaScriptCore/JavaScriptCore.exp b/Source/JavaScriptCore/JavaScriptCore.exp index c79c146e9..51032d742 100644 --- a/Source/JavaScriptCore/JavaScriptCore.exp +++ b/Source/JavaScriptCore/JavaScriptCore.exp @@ -91,6 +91,7 @@ _JSWeakObjectMapGet _JSWeakObjectMapRemove _JSWeakObjectMapSet _WTFGetBacktrace +_WTFInvokeCrashHook _WTFLog _WTFLogVerbose _WTFReportArgumentAssertionFailure @@ -99,6 +100,7 @@ _WTFReportAssertionFailureWithMessage _WTFReportBacktrace _WTFReportError _WTFReportFatalError +_WTFSetCrashHook __ZN14OpaqueJSString6createERKN3JSC7UStringE __ZN3JSC10HandleHeap12writeBarrierEPNS_7JSValueERKS1_ __ZN3JSC10HandleHeap4growEv @@ -110,6 +112,8 @@ __ZN3JSC10Identifier3addEPNS_9ExecStateEPKc __ZN3JSC10Identifier4fromEPNS_9ExecStateEi __ZN3JSC10Identifier4fromEPNS_9ExecStateEj __ZN3JSC10Identifier8toUInt32ERKNS_7UStringERb +__ZN3JSC10JSFunction11displayNameEPNS_9ExecStateE +__ZN3JSC10JSFunction21calculatedDisplayNameEPNS_9ExecStateE __ZN3JSC10JSFunction4nameEPNS_9ExecStateE __ZN3JSC10JSFunction6s_infoE __ZN3JSC10JSFunctionC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE @@ -125,6 +129,7 @@ __ZN3JSC11JSByteArray3putEPNS_6JSCellEPNS_9ExecStateERKNS_10IdentifierENS_7JSVal __ZN3JSC11JSByteArray6s_infoE __ZN3JSC11JSByteArray7destroyEPNS_6JSCellE __ZN3JSC11JSByteArrayC1EPNS_9ExecStateEPNS_9StructureEPN3WTF9ByteArrayE +__ZN3JSC11MarkedSpace16allocateSlowCaseERNS0_9SizeClassE __ZN3JSC11ParserArena5resetEv __ZN3JSC11checkSyntaxEPNS_9ExecStateERKNS_10SourceCodeEPNS_7JSValueE __ZN3JSC11createErrorEPNS_9ExecStateERKNS_7UStringE @@ -168,7 +173,7 @@ __ZN3JSC14JSGlobalObject12defineSetterEPNS_8JSObjectEPNS_9ExecStateERKNS_10Ident __ZN3JSC14JSGlobalObject13clearRareDataEPNS_6JSCellE __ZN3JSC14JSGlobalObject13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC14JSGlobalObject16addStaticGlobalsEPNS0_18GlobalPropertyInfoEi -__ZN3JSC14JSGlobalObject17putWithAttributesEPNS_8JSObjectEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj +__ZN3JSC14JSGlobalObject16putDirectVirtualEPNS_8JSObjectEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj __ZN3JSC14JSGlobalObject18getOwnPropertySlotEPNS_6JSCellEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE __ZN3JSC14JSGlobalObject24getOwnPropertyDescriptorEPNS_8JSObjectEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE __ZN3JSC14JSGlobalObject25s_globalObjectMethodTableE @@ -188,7 +193,6 @@ __ZN3JSC14TimeoutChecker5resetEv __ZN3JSC14VTableSpectrum5countEPNS_6JSCellE __ZN3JSC14throwTypeErrorEPNS_9ExecStateE __ZN3JSC14throwTypeErrorEPNS_9ExecStateERKNS_7UStringE -__ZN3JSC15AllocationSpace16allocateSlowCaseERNS_11MarkedSpace9SizeClassE __ZN3JSC15WeakHandleOwner26isReachableFromOpaqueRootsENS_6HandleINS_7UnknownEEEPvRNS_11SlotVisitorE __ZN3JSC15WeakHandleOwner8finalizeENS_6HandleINS_7UnknownEEEPv __ZN3JSC15WeakHandleOwnerD2Ev @@ -237,6 +241,7 @@ __ZN3JSC23setUpStaticFunctionSlotEPNS_9ExecStateEPKNS_9HashEntryEPNS_8JSObjectER __ZN3JSC24DynamicGlobalObjectScopeC1ERNS_12JSGlobalDataEPNS_14JSGlobalObjectE __ZN3JSC24TerminatedExecutionError6s_infoE __ZN3JSC24createStackOverflowErrorEPNS_9ExecStateE +__ZN3JSC24getCalculatedDisplayNameEPNS_9ExecStateEPNS_8JSObjectE __ZN3JSC25evaluateInGlobalCallFrameERKNS_7UStringERNS_7JSValueEPNS_14JSGlobalObjectE __ZN3JSC29callHostFunctionAsConstructorEPNS_9ExecStateE __ZN3JSC30isTerminatedExecutionExceptionENS_7JSValueE @@ -276,7 +281,7 @@ __ZN3JSC6JSLock4lockENS_14JSLockBehaviorE __ZN3JSC6JSLock6unlockENS_14JSLockBehaviorE __ZN3JSC6JSLock9lockCountEv __ZN3JSC6JSLockC1EPNS_9ExecStateE -__ZN3JSC6RegExp5matchERNS_12JSGlobalDataERKNS_7UStringEiPN3WTF6VectorIiLm32EEE +__ZN3JSC6RegExp5matchERNS_12JSGlobalDataERKNS_7UStringEjPN3WTF6VectorIiLm32EEE __ZN3JSC6RegExp6createERNS_12JSGlobalDataERKNS_7UStringENS_11RegExpFlagsE __ZN3JSC7JSArray13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC7JSArray14finishCreationERNS_12JSGlobalDataEj @@ -285,10 +290,8 @@ __ZN3JSC7JSArray17defineOwnPropertyEPNS_8JSObjectEPNS_9ExecStateERKNS_10Identifi __ZN3JSC7JSArray25getOwnPropertySlotByIndexEPNS_6JSCellEPNS_9ExecStateEjRNS_12PropertySlotE __ZN3JSC7JSArray30tryFinishCreationUninitializedERNS_12JSGlobalDataEj __ZN3JSC7JSArray6s_infoE -__ZN3JSC7JSArray7destroyEPNS_6JSCellE __ZN3JSC7JSArrayC1ERNS_12JSGlobalDataEPNS_9StructureE __ZN3JSC7JSArrayC2ERNS_12JSGlobalDataEPNS_9StructureE -__ZN3JSC7JSArrayD2Ev __ZN3JSC7JSValue13isValidCalleeEv __ZN3JSC7Options17numberOfGCMarkersE __ZN3JSC7Options24opaqueRootMergeThresholdE @@ -320,10 +323,9 @@ __ZN3JSC8JSObject12toThisObjectEPNS_6JSCellEPNS_9ExecStateE __ZN3JSC8JSObject13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC8JSObject14deletePropertyEPNS_6JSCellEPNS_9ExecStateERKNS_10IdentifierE __ZN3JSC8JSObject16getPropertyNamesEPS0_PNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE +__ZN3JSC8JSObject16putDirectVirtualEPS0_PNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj __ZN3JSC8JSObject17defineOwnPropertyEPS0_PNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorEb __ZN3JSC8JSObject17preventExtensionsERNS_12JSGlobalDataE -__ZN3JSC8JSObject17putWithAttributesEPNS_12JSGlobalDataERKNS_10IdentifierENS_7JSValueEj -__ZN3JSC8JSObject17putWithAttributesEPS0_PNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj __ZN3JSC8JSObject19getOwnPropertyNamesEPS0_PNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE __ZN3JSC8JSObject21deletePropertyByIndexEPNS_6JSCellEPNS_9ExecStateEj __ZN3JSC8JSObject21getPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE @@ -402,6 +404,7 @@ __ZN3WTF12AtomicString3addEPKh __ZN3WTF12AtomicString3addEPKt __ZN3WTF12AtomicString3addEPKtj __ZN3WTF12AtomicString3addEPKtjj +__ZN3WTF12AtomicString3addEPNS_10StringImplEjj __ZN3WTF12AtomicString4findEPKtjj __ZN3WTF12AtomicString4initEv __ZN3WTF12createThreadEPFPvS0_ES0_ @@ -410,11 +413,10 @@ __ZN3WTF12detachThreadEj __ZN3WTF12isMainThreadEv __ZN3WTF12randomNumberEv __ZN3WTF13MetaAllocator17addFreshFreeSpaceEPvm -__ZN3WTF13MetaAllocator17freeFreeSpaceNodeEPNS_12RedBlackTreeImPvE4NodeE +__ZN3WTF13MetaAllocator17freeFreeSpaceNodeEPNS0_13FreeSpaceNodeE __ZN3WTF13MetaAllocator18debugFreeSpaceSizeEv -__ZN3WTF13MetaAllocator8allocateEm +__ZN3WTF13MetaAllocator8allocateEmPv __ZN3WTF13MetaAllocatorC2Em -__ZN3WTF13StringBuilder11reifyStringEv __ZN3WTF13StringBuilder11shrinkToFitEv __ZN3WTF13StringBuilder15reserveCapacityEj __ZN3WTF13StringBuilder6appendEPKhj @@ -450,6 +452,7 @@ __ZN3WTF17equalIgnoringCaseEPNS_10StringImplEPKh __ZN3WTF17equalIgnoringCaseEPNS_10StringImplES1_ __ZN3WTF18calculateDSTOffsetEdd __ZN3WTF18calculateUTCOffsetEv +__ZN3WTF18charactersToDoubleEPKhmPbS2_ __ZN3WTF18charactersToDoubleEPKtmPbS2_ __ZN3WTF18dateToDaysFrom1970Eiii __ZN3WTF18monthFromDayInYearEib @@ -547,7 +550,6 @@ __ZN3WTF9xmlnsAtomE __ZN3WTFeqERKNS_7CStringES2_ __ZNK3JSC10JSFunction10sourceCodeEv __ZNK3JSC10JSFunction23isHostFunctionNonInlineEv -__ZNK3JSC11Interpreter14retrieveCallerEPNS_9ExecStateEPNS_10JSFunctionE __ZNK3JSC11Interpreter18retrieveLastCallerEPNS_9ExecStateERiRlRNS_7UStringERNS_7JSValueE __ZNK3JSC12PropertySlot14functionGetterEPNS_9ExecStateE __ZNK3JSC17DebuggerCallFrame10thisObjectEv @@ -566,13 +568,13 @@ __ZNK3JSC19SourceProviderCache8byteSizeEv __ZNK3JSC6JSCell11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE __ZNK3JSC6JSCell8toNumberEPNS_9ExecStateE __ZNK3JSC6JSCell8toObjectEPNS_9ExecStateEPNS_14JSGlobalObjectE -__ZNK3JSC6JSCell8toStringEPNS_9ExecStateE __ZNK3JSC6JSCell9getStringEPNS_9ExecStateE __ZNK3JSC6JSCell9getStringEPNS_9ExecStateERNS_7UStringE __ZNK3JSC7ArgList8getSliceEiRS0_ __ZNK3JSC7JSArray12subclassDataEv __ZNK3JSC7JSValue16toNumberSlowCaseEPNS_9ExecStateE __ZNK3JSC7JSValue16toObjectSlowCaseEPNS_9ExecStateEPNS_14JSGlobalObjectE +__ZNK3JSC7JSValue16toStringSlowCaseEPNS_9ExecStateE __ZNK3JSC7JSValue19synthesizePrototypeEPNS_9ExecStateE __ZNK3JSC7JSValue20toThisObjectSlowCaseEPNS_9ExecStateE __ZNK3JSC7JSValue9toIntegerEPNS_9ExecStateE @@ -596,6 +598,8 @@ __ZNK3WTF13DecimalNumber15toStringDecimalEPtj __ZNK3WTF13DecimalNumber19toStringExponentialEPtj __ZNK3WTF13DecimalNumber28bufferLengthForStringDecimalEv __ZNK3WTF13DecimalNumber32bufferLengthForStringExponentialEv +__ZNK3WTF13StringBuilder11reifyStringEv +__ZNK3WTF13StringBuilder9canShrinkEv __ZNK3WTF6String11toIntStrictEPbi __ZNK3WTF6String12isolatedCopyEv __ZNK3WTF6String12toUIntStrictEPbi diff --git a/Source/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp b/Source/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp index bec3ae17d..34b4e08e5 100644 --- a/Source/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp +++ b/Source/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp @@ -1,10 +1,10 @@ # -# Copyright (C) 2009 Google Inc. All rights reserved. -# +# Copyright (C) 2009, 2012 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: -# +# # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above @@ -14,7 +14,7 @@ # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. -# +# # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -30,8 +30,7 @@ { 'includes': [ - # FIXME: Sense whether upstream or downstream build, and - # include the right features.gypi + '../../WebKit/chromium/WinPrecompile.gypi', '../../WebKit/chromium/features.gypi', '../JavaScriptCore.gypi', ], @@ -66,7 +65,7 @@ 'defines': [ # Import features_defines from features.gypi '<@(feature_defines)', - + # Turns on #if PLATFORM(CHROMIUM) 'BUILDING_CHROMIUM__=1', # Controls wtf/FastMalloc @@ -123,18 +122,18 @@ ['exclude', '../'], # ... Then include what we want. ['include', '../wtf/'], - # FIXME: This is clearly not sustainable. - ['exclude', '../wtf/efl'], - ['exclude', '../wtf/gobject'], - ['exclude', '../wtf/gtk'], - ['exclude', '../wtf/mac'], - ['exclude', '../wtf/qt'], - ['exclude', '../wtf/url'], - ['exclude', '../wtf/wince'], - ['exclude', '../wtf/wx'], - ['exclude', '../wtf/unicode/wince'], - ['exclude', '../wtf/unicode/glib'], - ['exclude', '../wtf/unicode/qt4'], + # FIXME: This is clearly not sustainable. + ['exclude', '../wtf/efl'], + ['exclude', '../wtf/gobject'], + ['exclude', '../wtf/gtk'], + ['exclude', '../wtf/mac'], + ['exclude', '../wtf/qt'], + ['exclude', '../wtf/url'], + ['exclude', '../wtf/wince'], + ['exclude', '../wtf/wx'], + ['exclude', '../wtf/unicode/wince'], + ['exclude', '../wtf/unicode/glib'], + ['exclude', '../wtf/unicode/qt4'], # GLib/GTK, even though its name doesn't really indicate. ['exclude', '/(gtk|glib|gobject)/.*\\.(cpp|h)$'], ['exclude', '(Default|Gtk|Mac|None|Qt|Win|Wx|Efl|Symbian)\\.(cpp|mm)$'], @@ -172,7 +171,8 @@ ['exclude', 'ThreadingPthreads\\.cpp$'], ['include', 'Thread(ing|Specific)Win\\.cpp$'], ['exclude', 'OSAllocatorPosix\\.cpp$'], - ['include', 'OSAllocatorWin\\.cpp$'] + ['include', 'OSAllocatorWin\\.cpp$'], + ['include', 'win/OwnPtrWin\\.cpp$'], ], 'include_dirs!': [ '<(SHARED_INTERMEDIATE_DIR)/webkit', @@ -198,11 +198,6 @@ 'dependencies': [ 'wtf', ], - 'conditions': [ - ['OS=="win"', { - 'dependencies': ['<(chromium_src_dir)/build/win/system.gyp:cygwin'], - }], - ], 'variables': { 'optimize': 'max' }, 'actions': [ { diff --git a/Source/JavaScriptCore/JavaScriptCore.gypi b/Source/JavaScriptCore/JavaScriptCore.gypi index c9367911b..b59be38d9 100644 --- a/Source/JavaScriptCore/JavaScriptCore.gypi +++ b/Source/JavaScriptCore/JavaScriptCore.gypi @@ -27,10 +27,13 @@ 'API/OpaqueJSString.h', 'assembler/MacroAssemblerCodeRef.h', 'bytecode/Opcode.h', - 'heap/AllocationSpace.h', + 'heap/BumpBlock.h', + 'heap/BumpSpace.h', + 'heap/BumpSpaceInlineMethods.h', 'heap/ConservativeRoots.h', 'heap/Handle.h', 'heap/HandleHeap.h', + 'heap/HeapBlock.h', 'heap/SlotVisitor.h', 'heap/HandleStack.h', 'heap/HandleTypes.h', @@ -144,6 +147,7 @@ 'wtf/BumpPointerAllocator.h', 'wtf/ByteArray.h', 'wtf/CheckedArithmetic.h', + 'wtf/CheckedBoolean.h', 'wtf/Compiler.h', 'wtf/Complex.h', 'wtf/CryptographicallyRandomNumber.h', @@ -328,7 +332,6 @@ 'bytecompiler/LabelScope.h', 'bytecompiler/NodesCodegen.cpp', 'bytecompiler/RegisterID.h', - 'heap/AllocationSpace.cpp', 'heap/ConservativeRoots.cpp', 'heap/HandleHeap.cpp', 'heap/HandleStack.cpp', @@ -571,6 +574,8 @@ 'wtf/MainThread.cpp', 'wtf/MallocZoneSupport.h', 'wtf/NullPtr.cpp', + 'wtf/NumberOfCores.cpp', + 'wtf/NumberOfCores.h', 'wtf/OSAllocatorPosix.cpp', 'wtf/OSAllocatorWin.cpp', 'wtf/OSRandomSource.cpp', diff --git a/Source/JavaScriptCore/JavaScriptCore.order b/Source/JavaScriptCore/JavaScriptCore.order index 3ceda653e..d8513d099 100644 --- a/Source/JavaScriptCore/JavaScriptCore.order +++ b/Source/JavaScriptCore/JavaScriptCore.order @@ -323,7 +323,8 @@ __ZN3WTF13StringBuilder6appendEPKtj __ZN3WTF13StringBuilder19appendUninitializedEj __ZN3WTF13StringBuilder14allocateBufferEPKtj __ZN3WTF13StringBuilder11shrinkToFitEv -__ZN3WTF13StringBuilder11reifyStringEv +__ZNK3WTF13StringBuilder11reifyStringEv +__ZNK3WTF13StringBuilder9canShrinkEv __ZN3JSC7JSArray4pushEPNS_9ExecStateENS_7JSValueE __ZN3JSC7JSArray20increaseVectorLengthEj __ZN3WTF14tryFastReallocEPvm diff --git a/Source/JavaScriptCore/JavaScriptCore.pri b/Source/JavaScriptCore/JavaScriptCore.pri index 65e0eb31a..4e2426f8f 100644 --- a/Source/JavaScriptCore/JavaScriptCore.pri +++ b/Source/JavaScriptCore/JavaScriptCore.pri @@ -23,6 +23,7 @@ INCLUDEPATH += \ $$SOURCE_DIR/parser \ $$SOURCE_DIR/profiler \ $$SOURCE_DIR/runtime \ + $$SOURCE_DIR/tools \ $$SOURCE_DIR/yarr \ $$SOURCE_DIR/API \ $$SOURCE_DIR/ForwardingHeaders \ diff --git a/Source/JavaScriptCore/JavaScriptCore.pro b/Source/JavaScriptCore/JavaScriptCore.pro index cd3ab235f..393728f99 100644 --- a/Source/JavaScriptCore/JavaScriptCore.pro +++ b/Source/JavaScriptCore/JavaScriptCore.pro @@ -7,19 +7,13 @@ TEMPLATE = subdirs CONFIG += ordered -WTF.file = wtf/wtf.pro -WTF.makefile = Makefile.WTF -SUBDIRS += WTF +derived_sources.file = DerivedSources.pri +target.file = Target.pri -!v8 { - derived_sources.file = DerivedSources.pri - target.file = Target.pri +SUBDIRS += derived_sources target - SUBDIRS += derived_sources target +addStrictSubdirOrderBetween(derived_sources, target) - addStrictSubdirOrderBetween(derived_sources, target) - - jsc.file = jsc.pro - jsc.makefile = Makefile.jsc - SUBDIRS += jsc -} +jsc.file = jsc.pro +jsc.makefile = Makefile.jsc +SUBDIRS += jsc diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index 577329e94..93c9e7569 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -64,7 +64,7 @@ EXPORTS ?addSlowCase@Identifier@JSC@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVJSGlobalData@2@PAVStringImpl@4@@Z ?addStaticGlobals@JSGlobalObject@JSC@@IAEXPAUGlobalPropertyInfo@12@H@Z ?allocatePropertyStorage@JSObject@JSC@@QAEXAAVJSGlobalData@2@II@Z - ?allocateSlowCase@AllocationSpace@JSC@@AAEPAXAAUSizeClass@MarkedSpace@2@@Z + ?allocateSlowCase@MarkedSpace@JSC@@AAEPAXAAUSizeClass@12@@Z ?append@StringBuilder@WTF@@QAEXPBEI@Z ?append@StringBuilder@WTF@@QAEXPB_WI@Z ?ascii@UString@JSC@@QBE?AVCString@WTF@@XZ @@ -158,6 +158,7 @@ EXPORTS ?detach@Debugger@JSC@@UAEXPAVJSGlobalObject@2@@Z ?detachThread@WTF@@YAXI@Z ?didTimeOut@TimeoutChecker@JSC@@QAE_NPAVExecState@2@@Z + ?displayName@JSFunction@JSC@@QAE?BVUString@2@PAVExecState@2@@Z ?dtoa@WTF@@YAXQADNAA_NAAHAAI@Z ?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z ?empty@StringImpl@WTF@@SAPAV12@XZ @@ -243,7 +244,7 @@ EXPORTS ?lock@Mutex@WTF@@QAEXXZ ?lockAtomicallyInitializedStaticMutex@WTF@@YAXXZ ?lockCount@JSLock@JSC@@SAHXZ - ?match@RegExp@JSC@@QAEHAAVJSGlobalData@2@ABVUString@2@HPAV?$Vector@H$0CA@@WTF@@@Z + ?match@RegExp@JSC@@QAEHAAVJSGlobalData@2@ABVUString@2@IPAV?$Vector@H$0CA@@WTF@@@Z ?materializePropertyMap@Structure@JSC@@AAEXAAVJSGlobalData@2@@Z ?monotonicallyIncreasingTime@WTF@@YANXZ ?monthFromDayInYear@WTF@@YAHH_N@Z @@ -274,13 +275,12 @@ EXPORTS ?put@JSObject@JSC@@SAXPAVJSCell@2@PAVExecState@2@ABVIdentifier@2@VJSValue@2@AAVPutPropertySlot@2@@Z ?putByIndex@JSByteArray@JSC@@SAXPAVJSCell@2@PAVExecState@2@IVJSValue@2@@Z ?putByIndex@JSObject@JSC@@SAXPAVJSCell@2@PAVExecState@2@IVJSValue@2@@Z - ?putDirectInternal@JSObject@JSC@@AAE_NAAVJSGlobalData@2@ABVIdentifier@2@VJSValue@2@I_NAAVPutPropertySlot@2@PAVJSCell@2@@Z - ?putWithAttributes@JSGlobalObject@JSC@@SAXPAVJSObject@2@PAVExecState@2@ABVIdentifier@2@VJSValue@2@I@Z - ?putWithAttributes@JSObject@JSC@@SAXPAV12@PAVExecState@2@ABVIdentifier@2@VJSValue@2@I@Z + ?putDirectVirtual@JSGlobalObject@JSC@@SAXPAVJSObject@2@PAVExecState@2@ABVIdentifier@2@VJSValue@2@I@Z + ?putDirectVirtual@JSObject@JSC@@SAXPAV12@PAVExecState@2@ABVIdentifier@2@VJSValue@2@I@Z ?randomNumber@WTF@@YANXZ ?recompileAllJSFunctions@Debugger@JSC@@QAEXPAVJSGlobalData@2@@Z ?regExpFlags@JSC@@YA?AW4RegExpFlags@1@ABVUString@1@@Z - ?reifyString@StringBuilder@WTF@@AAEXXZ + ?reifyString@StringBuilder@WTF@@ABEXXZ ?releaseDecommitted@OSAllocator@WTF@@SAXPAXI@Z ?releaseExecutableMemory@JSGlobalData@JSC@@QAEXXZ ?reportExtraMemoryCostSlowCase@Heap@JSC@@AAEXI@Z @@ -292,11 +292,9 @@ EXPORTS ?resize@StringBuilder@WTF@@QAEXI@Z ?resolveRope@JSString@JSC@@ABEXPAVExecState@2@@Z ?restoreAll@Profile@JSC@@QAEXXZ - ?retrieveCaller@Interpreter@JSC@@QBE?AVJSValue@2@PAVExecState@2@PAVJSFunction@2@@Z + ?retrieveCallerFromVMCode@Interpreter@JSC@@QBE?AVJSValue@2@PAVExecState@2@PAVJSFunction@2@@Z ?retrieveLastCaller@Interpreter@JSC@@QBEXPAVExecState@2@AAH1AAVUString@2@AAVJSValue@2@@Z ?s_globalObjectMethodTable@JSGlobalObject@JSC@@1UGlobalObjectMethodTable@2@B - ?s_info@ExecutableBase@JSC@@2UClassInfo@2@B - ?s_info@JSString@JSC@@2UClassInfo@2@B ?setConfigurable@PropertyDescriptor@JSC@@QAEX_N@Z ?setDescriptor@PropertyDescriptor@JSC@@QAEXVJSValue@2@I@Z ?setDumpsGeneratedCode@BytecodeGenerator@JSC@@SAX_N@Z @@ -342,10 +340,10 @@ EXPORTS ?toNumberSlowCase@JSValue@JSC@@ABENPAVExecState@2@@Z ?toObject@JSCell@JSC@@QBEPAVJSObject@2@PAVExecState@2@PAVJSGlobalObject@2@@Z ?toObjectSlowCase@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@PAVJSGlobalObject@2@@Z - ?toString@JSCell@JSC@@QBE?AVUString@2@PAVExecState@2@@Z - ?toString@JSObject@JSC@@QBE?AVUString@2@PAVExecState@2@@Z + ?toString@JSObject@JSC@@QBEPAVJSString@2@PAVExecState@2@@Z ?toStringDecimal@DecimalNumber@WTF@@QBEIPA_WI@Z ?toStringExponential@DecimalNumber@WTF@@QBEIPA_WI@Z + ?toStringSlowCase@JSValue@JSC@@ABEPAVJSString@2@PAVExecState@2@@Z ?toThisObject@JSObject@JSC@@SAPAV12@PAVJSCell@2@PAVExecState@2@@Z ?toThisObjectSlowCase@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z ?toUInt32@Identifier@JSC@@SAIABVUString@2@AA_N@Z @@ -370,6 +368,7 @@ EXPORTS ?writeBarrier@HandleHeap@JSC@@QAEXPAVJSValue@2@ABV32@@Z ?yield@WTF@@YAXXZ WTFGetBacktrace + WTFInvokeCrashHook WTFLog WTFLogVerbose WTFReportArgumentAssertionFailure @@ -377,3 +376,4 @@ EXPORTS WTFReportAssertionFailureWithMessage WTFReportBacktrace WTFReportError + WTFSetCrashHook diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj index 8fd3c8ab0..fea820ddc 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -1447,9 +1447,69 @@ </File> </Filter> <Filter + Name="tools" + > + <File + RelativePath="..\..\tools\CodeProfile.cpp" + > + </File> + <File + RelativePath="..\..\tools\CodeProfile.h" + > + </File> + <File + RelativePath="..\..\tools\CodeProfiling.cpp" + > + </File> + <File + RelativePath="..\..\tools\CodeProfiling.h" + > + </File> + <File + RelativePath="..\..\tools\ProfileTreeNode.h" + > + </File> + <File + RelativePath="..\..\tools\TieredMMapArray.h" + > + </File> + </Filter> + <Filter Name="bytecode" > <File + RelativePath="..\..\bytecode\GetByIdStatus.h" + > + </File> + <File + RelativePath="..\..\bytecode\PutByIdStatus.h" + > + </File> + <File + RelativePath="..\..\bytecode\CallLinkStatus.h" + > + </File> + <File + RelativePath="..\..\bytecode\MethodCallLinkStatus.h" + > + </File> + <File + RelativePath="..\..\bytecode\GetByIdStatus.cpp" + > + </File> + <File + RelativePath="..\..\bytecode\PutByIdStatus.cpp" + > + </File> + <File + RelativePath="..\..\bytecode\CallLinkStatus.cpp" + > + </File> + <File + RelativePath="..\..\bytecode\MethodCallLinkStatus.cpp" + > + </File> + <File RelativePath="..\..\bytecode\HandlerInfo.h" > </File> @@ -1786,6 +1846,14 @@ Name="interpreter" > <File + RelativePath="..\..\interpreter\AbstractPC.cpp" + > + </File> + <File + RelativePath="..\..\interpreter\AbstractPC.h" + > + </File> + <File RelativePath="..\..\interpreter\CachedCall.h" > </File> @@ -1966,11 +2034,19 @@ Name="heap" > <File - RelativePath="..\..\heap\AllocationSpace.cpp" + RelativePath="..\..\heap\BumpBlock.h" > </File> <File - RelativePath="..\..\heap\AllocationSpace.h" + RelativePath="..\..\heap\BumpSpace.cpp" + > + </File> + <File + RelativePath="..\..\heap\BumpSpace.h" + > + </File> + <File + RelativePath="..\..\heap\BumpSpaceInlineMethods.h" > </File> <File @@ -2026,6 +2102,10 @@ > </File> <File + RelativePath="..\..\heap\HeapBlock.h" + > + </File> + <File RelativePath="..\..\heap\Strong.h" > </File> diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops index e94459681..33b53442a 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops @@ -6,7 +6,7 @@ > <Tool Name="VCCLCompilerTool" - AdditionalIncludeDirectories=""$(ConfigurationBuildDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../parser/;../../bytecompiler/;../../dfg/;../../jit/;../../runtime/;../../bytecode/;../../interpreter/;../../wtf/;../../profiler;../../assembler/;../../debugger/;../../heap/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\private";"$(ConfigurationBuildDir)\include";"$(ConfigurationBuildDir)\include\JavaScriptCore";"$(ConfigurationBuildDir)\include\private";"$(WebKitLibrariesDir)\include\pthreads"" + AdditionalIncludeDirectories=""$(ConfigurationBuildDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../parser/;../../bytecompiler/;../../dfg/;../../jit/;../../runtime/;../../tools/;../../bytecode/;../../interpreter/;../../wtf/;../../profiler;../../assembler/;../../debugger/;../../heap/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\private";"$(ConfigurationBuildDir)\include";"$(ConfigurationBuildDir)\include\JavaScriptCore";"$(ConfigurationBuildDir)\include\private";"$(WebKitLibrariesDir)\include\pthreads"" PreprocessorDefinitions="__STD_C" ForcedIncludeFiles="ICUVersion.h" /> diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj index 6e89b0167..c914b22c1 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj @@ -693,6 +693,10 @@ > </File> <File + RelativePath="..\..\wtf\CheckedBoolean.h" + > + </File> + <File RelativePath="..\..\wtf\Compiler.h" > </File> @@ -949,6 +953,14 @@ > </File> <File + RelativePath="..\..\wtf\NumberOfCores.cpp" + > + </File> + <File + RelativePath="..\..\wtf\NumberOfCores.h" + > + </File> + <File RelativePath="..\..\wtf\OSAllocatorWin.cpp" > </File> diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 8685f097f..9d8b3dd58 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -60,6 +60,7 @@ 0F0B83B914BCF95F00885B4F /* CallReturnOffsetToBytecodeOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F15F15F14B7A73E005DE37D /* CommonSlowPaths.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F16D726142C39C000CF784A /* BitVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F16D724142C39A200CF784A /* BitVector.cpp */; }; + 0F21C26814BE5F6800ADC64B /* JITDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F21C26614BE5F5E00ADC64B /* JITDriver.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F242DA713F3B1E8007ADD4C /* WeakReferenceHarvester.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2C556F14738F3100121E4F /* DFGCodeBlocks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2C557014738F3500121E4F /* DFGCodeBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */; }; @@ -70,6 +71,8 @@ 0F431738146BAC69007E3890 /* ListableHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F431736146BAC65007E3890 /* ListableHandler.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F46808214BA572D00BFE272 /* JITExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F46808014BA572700BFE272 /* JITExceptions.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F46808314BA573100BFE272 /* JITExceptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F46807F14BA572700BFE272 /* JITExceptions.cpp */; }; + 0F55F0F414D1063900AC7649 /* AbstractPC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F55F0F114D1063600AC7649 /* AbstractPC.cpp */; }; + 0F55F0F514D1063C00AC7649 /* AbstractPC.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F55F0F214D1063600AC7649 /* AbstractPC.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F5F08CF146C7633000472A9 /* UnconditionalFinalizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5F08CE146C762F000472A9 /* UnconditionalFinalizer.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F620174143FCD330068B77C /* DFGVariableAccessData.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F620175143FCD370068B77C /* DFGOperands.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F620171143FCD2F0068B77C /* DFGOperands.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -79,6 +82,19 @@ 0F620179143FCD480068B77C /* DFGAbstractState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */; }; 0F636DA0142D27D700B2E66A /* PackedIntVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F636D9F142D27D200B2E66A /* PackedIntVector.h */; }; 0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7700911402FF280078EB39 /* SamplingCounter.cpp */; }; + 0F7B294A14C3CD29007C3DB1 /* DFGCCallHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7B294814C3CD23007C3DB1 /* DFGCCallHelpers.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E1F14172C2F00179C94 /* DFGCapabilities.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F7B294C14C3CD43007C3DB1 /* DFGByteCodeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5F08CC146BE602000472A9 /* DFGByteCodeCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC0977E1469EBC400CF2442 /* DFGCommon.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F93329D14CA7DC30085F3C6 /* CallLinkStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */; }; + 0F93329E14CA7DC50085F3C6 /* CallLinkStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F93329F14CA7DCA0085F3C6 /* GetByIdStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */; }; + 0F9332A014CA7DCD0085F3C6 /* GetByIdStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F9332A114CA7DD10085F3C6 /* MethodCallLinkStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329714CA7DC10085F3C6 /* MethodCallLinkStatus.cpp */; }; + 0F9332A214CA7DD30085F3C6 /* MethodCallLinkStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329814CA7DC10085F3C6 /* MethodCallLinkStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F9332A314CA7DD70085F3C6 /* PutByIdStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */; }; + 0F9332A414CA7DD90085F3C6 /* PutByIdStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F9332A514CA7DDD0085F3C6 /* StructureSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329B14CA7DC10085F3C6 /* StructureSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F963B2713F753BB0002D9B2 /* RedBlackTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B2613F753990002D9B2 /* RedBlackTree.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F963B2C13F853EC0002D9B2 /* MetaAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F963B2B13F853C70002D9B2 /* MetaAllocator.cpp */; settings = {COMPILER_FLAGS = "-fno-strict-aliasing"; }; }; 0F963B2D13F854020002D9B2 /* MetaAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B2A13F853BD0002D9B2 /* MetaAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -120,7 +136,6 @@ 0FD82F4B142806A100179C94 /* BitVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82F491428069200179C94 /* BitVector.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; }; - 0FFF4BB4143955E900655BC0 /* DFGStructureSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFF4BB2143955E600655BC0 /* DFGStructureSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1400067712A6F7830064D123 /* OSAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 1400067612A6F7830064D123 /* OSAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1400069312A6F9E10064D123 /* OSAllocatorPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */; }; 140566C4107EC255005DBC8D /* JSAPIValueWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0894D50FAFBA2D00001865 /* JSAPIValueWrapper.cpp */; }; @@ -367,6 +382,8 @@ 86AE64AA135E5E1C00963012 /* SH4Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE64A7135E5E1C00963012 /* SH4Assembler.h */; }; 86AE6C4D136A11E400963012 /* DFGFPRInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE6C4B136A11E400963012 /* DFGFPRInfo.h */; }; 86AE6C4E136A11E400963012 /* DFGGPRInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE6C4C136A11E400963012 /* DFGGPRInfo.h */; }; + 86B5826714D2796C00A9C306 /* CodeProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86B5822E14D2373B00A9C306 /* CodeProfile.cpp */; }; + 86B5826914D2797000A9C306 /* CodeProfiling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8603CEF214C7546400AE59E3 /* CodeProfiling.cpp */; }; 86B99AE3117E578100DF5A90 /* StringBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 86B99AE1117E578100DF5A90 /* StringBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86BB09C0138E381B0056702F /* DFGRepatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86BB09BE138E381B0056702F /* DFGRepatch.cpp */; }; 86BB09C1138E381B0056702F /* DFGRepatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BB09BF138E381B0056702F /* DFGRepatch.h */; }; @@ -414,6 +431,7 @@ 90213E3E123A40C200D422F3 /* MemoryStatistics.h in Headers */ = {isa = PBXBuildFile; fileRef = 90213E3C123A40C200D422F3 /* MemoryStatistics.h */; settings = {ATTRIBUTES = (Private, ); }; }; 905B02AE0E28640F006DF882 /* RefCountedLeakCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 905B02AD0E28640F006DF882 /* RefCountedLeakCounter.cpp */; }; 90D3469C0E285280009492EE /* RefCountedLeakCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D3469B0E285280009492EE /* RefCountedLeakCounter.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 91A3905614C0F47200F67901 /* Uint8ClampedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 91A3905514C0F47200F67901 /* Uint8ClampedArray.h */; settings = {ATTRIBUTES = (Private, ); }; }; 93052C340FB792190048FDC3 /* ParserArena.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93052C320FB792190048FDC3 /* ParserArena.cpp */; }; 93052C350FB792190048FDC3 /* ParserArena.h in Headers */ = {isa = PBXBuildFile; fileRef = 93052C330FB792190048FDC3 /* ParserArena.h */; settings = {ATTRIBUTES = (Private, ); }; }; 932F5BD30822A1C700736975 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6560A4CF04B3B3E7008AE952 /* CoreFoundation.framework */; }; @@ -460,8 +478,6 @@ A1712B3F11C7B228007A5315 /* RegExpCache.h in Headers */ = {isa = PBXBuildFile; fileRef = A1712B3E11C7B228007A5315 /* RegExpCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; A1712B4111C7B235007A5315 /* RegExpKey.h in Headers */ = {isa = PBXBuildFile; fileRef = A1712B4011C7B235007A5315 /* RegExpKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; A1D764521354448B00C5C7C0 /* Alignment.h in Headers */ = {isa = PBXBuildFile; fileRef = A1D764511354448B00C5C7C0 /* Alignment.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A70456B01427FB910037DA68 /* AllocationSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = A70456AF1427FB150037DA68 /* AllocationSpace.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A70456B11427FB950037DA68 /* AllocationSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A70456AE1427FB030037DA68 /* AllocationSpace.cpp */; }; A71236E51195F33C00BD2174 /* JITOpcodes32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A71236E41195F33C00BD2174 /* JITOpcodes32_64.cpp */; }; A72700900DAC6BBC00E548D7 /* JSNotAnObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A72700780DAC605600E548D7 /* JSNotAnObject.cpp */; }; A72701B90DADE94900E548D7 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; }; @@ -704,6 +720,12 @@ C22C531313FAF6EF00B7DC0D /* strtod.cc in Sources */ = {isa = PBXBuildFile; fileRef = C22C52B913FAF6EF00B7DC0D /* strtod.cc */; }; C22C531413FAF6EF00B7DC0D /* strtod.h in Headers */ = {isa = PBXBuildFile; fileRef = C22C52BA13FAF6EF00B7DC0D /* strtod.h */; settings = {ATTRIBUTES = (Private, ); }; }; C22C531513FAF6EF00B7DC0D /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = C22C52BB13FAF6EF00B7DC0D /* utils.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C240305514B404E60079EB64 /* BumpSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C240305314B404C90079EB64 /* BumpSpace.cpp */; }; + C2C8D02D14A3C6E000578E65 /* BumpSpaceInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02B14A3C6B200578E65 /* BumpSpaceInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C2C8D03014A3CEFC00578E65 /* BumpBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02E14A3CEFC00578E65 /* BumpBlock.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C2C8D03114A3CEFC00578E65 /* HeapBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C2D9CA1314BCC04600304B46 /* CheckedBoolean.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D9CA1214BCC04600304B46 /* CheckedBoolean.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C2EAA3FA149A835E00FCE112 /* BumpSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EAA3F8149A830800FCE112 /* BumpSpace.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2EE59A013FC973F009CEAFE /* DecimalNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EE599E13FC972A009CEAFE /* DecimalNumber.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2EE59A113FC9768009CEAFE /* DecimalNumber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2EE599D13FC972A009CEAFE /* DecimalNumber.cpp */; }; D7A46A4F1338FFEA00ED695C /* DynamicAnnotations.h in Headers */ = {isa = PBXBuildFile; fileRef = D75AF59612F8CB9500FC0ADF /* DynamicAnnotations.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -725,6 +747,8 @@ E49DC16D12EF295300184A1F /* SourceProviderCacheItem.h in Headers */ = {isa = PBXBuildFile; fileRef = E49DC14912EF261A00184A1F /* SourceProviderCacheItem.h */; settings = {ATTRIBUTES = (Private, ); }; }; E4D8CEFB12FC439600BC9F5A /* BloomFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = E4D8CE9B12FC42E100BC9F5A /* BloomFilter.h */; settings = {ATTRIBUTES = (Private, ); }; }; F3BD31ED126735770065467F /* TextPosition.h in Headers */ = {isa = PBXBuildFile; fileRef = F3BD31D0126730180065467F /* TextPosition.h */; settings = {ATTRIBUTES = (Private, ); }; }; + F69E86C314C6E551002C2C62 /* NumberOfCores.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F69E86C114C6E551002C2C62 /* NumberOfCores.cpp */; }; + F69E86C414C6E551002C2C62 /* NumberOfCores.h in Headers */ = {isa = PBXBuildFile; fileRef = F69E86C214C6E551002C2C62 /* NumberOfCores.h */; }; FDA15C1E12B0305C003A583A /* Complex.h in Headers */ = {isa = PBXBuildFile; fileRef = FDA15C1612B03028003A583A /* Complex.h */; settings = {ATTRIBUTES = (Private, ); }; }; FE1B447A0ECCD73B004F4DD1 /* StdLibExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = FE1B44790ECCD73B004F4DD1 /* StdLibExtras.h */; settings = {ATTRIBUTES = (Private, ); }; }; /* End PBXBuildFile section */ @@ -827,6 +851,7 @@ 0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallReturnOffsetToBytecodeOffset.h; sourceTree = "<group>"; }; 0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonSlowPaths.h; sourceTree = "<group>"; }; 0F16D724142C39A200CF784A /* BitVector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BitVector.cpp; sourceTree = "<group>"; }; + 0F21C26614BE5F5E00ADC64B /* JITDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITDriver.h; sourceTree = "<group>"; }; 0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakReferenceHarvester.h; sourceTree = "<group>"; }; 0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DFGCodeBlocks.cpp; sourceTree = "<group>"; }; 0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFGCodeBlocks.h; sourceTree = "<group>"; }; @@ -837,6 +862,8 @@ 0F431736146BAC65007E3890 /* ListableHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ListableHandler.h; sourceTree = "<group>"; }; 0F46807F14BA572700BFE272 /* JITExceptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITExceptions.cpp; sourceTree = "<group>"; }; 0F46808014BA572700BFE272 /* JITExceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITExceptions.h; sourceTree = "<group>"; }; + 0F55F0F114D1063600AC7649 /* AbstractPC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AbstractPC.cpp; sourceTree = "<group>"; }; + 0F55F0F214D1063600AC7649 /* AbstractPC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbstractPC.h; sourceTree = "<group>"; }; 0F5F08CC146BE602000472A9 /* DFGByteCodeCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGByteCodeCache.h; path = dfg/DFGByteCodeCache.h; sourceTree = "<group>"; }; 0F5F08CE146C762F000472A9 /* UnconditionalFinalizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnconditionalFinalizer.h; sourceTree = "<group>"; }; 0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGAbstractState.cpp; path = dfg/DFGAbstractState.cpp; sourceTree = "<group>"; }; @@ -848,6 +875,16 @@ 0F636D9F142D27D200B2E66A /* PackedIntVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PackedIntVector.h; sourceTree = "<group>"; }; 0F77008E1402FDD60078EB39 /* SamplingCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingCounter.h; sourceTree = "<group>"; }; 0F7700911402FF280078EB39 /* SamplingCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingCounter.cpp; sourceTree = "<group>"; }; + 0F7B294814C3CD23007C3DB1 /* DFGCCallHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCCallHelpers.h; path = dfg/DFGCCallHelpers.h; sourceTree = "<group>"; }; + 0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallLinkStatus.cpp; sourceTree = "<group>"; }; + 0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallLinkStatus.h; sourceTree = "<group>"; }; + 0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetByIdStatus.cpp; sourceTree = "<group>"; }; + 0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetByIdStatus.h; sourceTree = "<group>"; }; + 0F93329714CA7DC10085F3C6 /* MethodCallLinkStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MethodCallLinkStatus.cpp; sourceTree = "<group>"; }; + 0F93329814CA7DC10085F3C6 /* MethodCallLinkStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MethodCallLinkStatus.h; sourceTree = "<group>"; }; + 0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PutByIdStatus.cpp; sourceTree = "<group>"; }; + 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByIdStatus.h; sourceTree = "<group>"; }; + 0F93329B14CA7DC10085F3C6 /* StructureSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureSet.h; sourceTree = "<group>"; }; 0F963B2613F753990002D9B2 /* RedBlackTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RedBlackTree.h; sourceTree = "<group>"; }; 0F963B2A13F853BD0002D9B2 /* MetaAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MetaAllocator.h; sourceTree = "<group>"; }; 0F963B2B13F853C70002D9B2 /* MetaAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MetaAllocator.cpp; sourceTree = "<group>"; }; @@ -891,7 +928,6 @@ 0FD82F491428069200179C94 /* BitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitVector.h; sourceTree = "<group>"; }; 0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; }; 0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; }; - 0FFF4BB2143955E600655BC0 /* DFGStructureSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureSet.h; path = dfg/DFGStructureSet.h; sourceTree = "<group>"; }; 1400067612A6F7830064D123 /* OSAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSAllocator.h; sourceTree = "<group>"; }; 1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OSAllocatorPosix.cpp; sourceTree = "<group>"; }; 140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBasePrivate.h; sourceTree = "<group>"; }; @@ -1008,7 +1044,7 @@ 1A082778142168D70090CCAC /* BinarySemaphore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BinarySemaphore.h; sourceTree = "<group>"; }; 1AA9E5501498093500001A8A /* Functional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Functional.h; sourceTree = "<group>"; }; 1C9051420BA9E8A70081E9D0 /* Version.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Version.xcconfig; sourceTree = "<group>"; }; - 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = JavaScriptCore.xcconfig; path = ../Configurations/JavaScriptCore.xcconfig; sourceTree = "<group>"; }; + 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = JavaScriptCore.xcconfig; sourceTree = "<group>"; }; 1C9051440BA9E8A70081E9D0 /* DebugRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugRelease.xcconfig; sourceTree = "<group>"; }; 1C9051450BA9E8A70081E9D0 /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; }; 1CAA8B4A0D32C39A0041BCFF /* JavaScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScript.h; sourceTree = "<group>"; }; @@ -1104,6 +1140,8 @@ 860161E00F3A83C100F84710 /* MacroAssemblerX86.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerX86.h; sourceTree = "<group>"; }; 860161E10F3A83C100F84710 /* MacroAssemblerX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerX86_64.h; sourceTree = "<group>"; }; 860161E20F3A83C100F84710 /* MacroAssemblerX86Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerX86Common.h; sourceTree = "<group>"; }; + 8603CEF214C7546400AE59E3 /* CodeProfiling.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeProfiling.cpp; sourceTree = "<group>"; }; + 8603CEF314C7546400AE59E3 /* CodeProfiling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeProfiling.h; sourceTree = "<group>"; }; 8604F4F2143A6C4400B295F5 /* ChangeLog */ = {isa = PBXFileReference; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; }; 8604F503143CE1C100B295F5 /* JSGlobalThis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalThis.h; sourceTree = "<group>"; }; 8626BECE11928E3900782FAB /* StringStatics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringStatics.cpp; path = text/StringStatics.cpp; sourceTree = "<group>"; }; @@ -1151,6 +1189,10 @@ 86AE64A7135E5E1C00963012 /* SH4Assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SH4Assembler.h; sourceTree = "<group>"; }; 86AE6C4B136A11E400963012 /* DFGFPRInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGFPRInfo.h; path = dfg/DFGFPRInfo.h; sourceTree = "<group>"; }; 86AE6C4C136A11E400963012 /* DFGGPRInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGGPRInfo.h; path = dfg/DFGGPRInfo.h; sourceTree = "<group>"; }; + 86B5822C14D22F5F00A9C306 /* ProfileTreeNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProfileTreeNode.h; sourceTree = "<group>"; }; + 86B5822E14D2373B00A9C306 /* CodeProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeProfile.cpp; sourceTree = "<group>"; }; + 86B5822F14D2373B00A9C306 /* CodeProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeProfile.h; sourceTree = "<group>"; }; + 86B5826A14D35D5100A9C306 /* TieredMMapArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TieredMMapArray.h; sourceTree = "<group>"; }; 86B99AE1117E578100DF5A90 /* StringBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringBuffer.h; path = text/StringBuffer.h; sourceTree = "<group>"; }; 86BB09BE138E381B0056702F /* DFGRepatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGRepatch.cpp; path = dfg/DFGRepatch.cpp; sourceTree = "<group>"; }; 86BB09BF138E381B0056702F /* DFGRepatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGRepatch.h; path = dfg/DFGRepatch.h; sourceTree = "<group>"; }; @@ -1199,6 +1241,7 @@ 90213E3C123A40C200D422F3 /* MemoryStatistics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryStatistics.h; sourceTree = "<group>"; }; 905B02AD0E28640F006DF882 /* RefCountedLeakCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RefCountedLeakCounter.cpp; sourceTree = "<group>"; }; 90D3469B0E285280009492EE /* RefCountedLeakCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefCountedLeakCounter.h; sourceTree = "<group>"; }; + 91A3905514C0F47200F67901 /* Uint8ClampedArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Uint8ClampedArray.h; sourceTree = "<group>"; }; 9303F567099118FA00AD71B8 /* OwnPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OwnPtr.h; sourceTree = "<group>"; }; 9303F5690991190000AD71B8 /* Noncopyable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Noncopyable.h; sourceTree = "<group>"; }; 9303F5A409911A5800AD71B8 /* OwnArrayPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OwnArrayPtr.h; sourceTree = "<group>"; }; @@ -1272,8 +1315,6 @@ A1712B3E11C7B228007A5315 /* RegExpCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpCache.h; sourceTree = "<group>"; }; A1712B4011C7B235007A5315 /* RegExpKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpKey.h; sourceTree = "<group>"; }; A1D764511354448B00C5C7C0 /* Alignment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Alignment.h; sourceTree = "<group>"; }; - A70456AE1427FB030037DA68 /* AllocationSpace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AllocationSpace.cpp; sourceTree = "<group>"; }; - A70456AF1427FB150037DA68 /* AllocationSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AllocationSpace.h; sourceTree = "<group>"; }; A71236E41195F33C00BD2174 /* JITOpcodes32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITOpcodes32_64.cpp; sourceTree = "<group>"; }; A718F61A11754A21002465A7 /* RegExpJitTables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpJitTables.h; sourceTree = "<group>"; }; A718F8211178EB4B002465A7 /* create_regex_tables */ = {isa = PBXFileReference; explicitFileType = text.script.python; fileEncoding = 4; path = create_regex_tables; sourceTree = "<group>"; }; @@ -1464,6 +1505,12 @@ C22C52B913FAF6EF00B7DC0D /* strtod.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strtod.cc; sourceTree = "<group>"; }; C22C52BA13FAF6EF00B7DC0D /* strtod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strtod.h; sourceTree = "<group>"; }; C22C52BB13FAF6EF00B7DC0D /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = "<group>"; }; + C240305314B404C90079EB64 /* BumpSpace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BumpSpace.cpp; sourceTree = "<group>"; }; + C2C8D02B14A3C6B200578E65 /* BumpSpaceInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BumpSpaceInlineMethods.h; sourceTree = "<group>"; }; + C2C8D02E14A3CEFC00578E65 /* BumpBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BumpBlock.h; sourceTree = "<group>"; }; + C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapBlock.h; sourceTree = "<group>"; }; + C2D9CA1214BCC04600304B46 /* CheckedBoolean.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CheckedBoolean.h; sourceTree = "<group>"; }; + C2EAA3F8149A830800FCE112 /* BumpSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BumpSpace.h; sourceTree = "<group>"; }; C2EE599D13FC972A009CEAFE /* DecimalNumber.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DecimalNumber.cpp; sourceTree = "<group>"; }; C2EE599E13FC972A009CEAFE /* DecimalNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DecimalNumber.h; sourceTree = "<group>"; }; D21202280AD4310C00ED79B6 /* DateConversion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DateConversion.cpp; sourceTree = "<group>"; }; @@ -1533,6 +1580,8 @@ F692A8850255597D01FF60F7 /* UString.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UString.cpp; sourceTree = "<group>"; tabWidth = 8; }; F692A8860255597D01FF60F7 /* UString.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = UString.h; sourceTree = "<group>"; tabWidth = 8; }; F692A8870255597D01FF60F7 /* JSValue.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSValue.cpp; sourceTree = "<group>"; tabWidth = 8; }; + F69E86C114C6E551002C2C62 /* NumberOfCores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NumberOfCores.cpp; path = wtf/NumberOfCores.cpp; sourceTree = "<group>"; }; + F69E86C214C6E551002C2C62 /* NumberOfCores.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NumberOfCores.h; path = wtf/NumberOfCores.h; sourceTree = "<group>"; }; FDA15C1612B03028003A583A /* Complex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Complex.h; sourceTree = "<group>"; }; FE1B44790ECCD73B004F4DD1 /* StdLibExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StdLibExtras.h; sourceTree = "<group>"; }; /* End PBXFileReference section */ @@ -1613,6 +1662,8 @@ 0867D691FE84028FC02AAC07 /* JavaScriptCore */ = { isa = PBXGroup; children = ( + F69E86C114C6E551002C2C62 /* NumberOfCores.cpp */, + F69E86C214C6E551002C2C62 /* NumberOfCores.h */, 8604F4F2143A6C4400B295F5 /* ChangeLog */, A718F8211178EB4B002465A7 /* create_regex_tables */, 937B63CC09E766D200A671DD /* DerivedSources.make */, @@ -1637,6 +1688,7 @@ 95AB831A0DA42C6900BC83F3 /* profiler */, 7EF6E0BB0EB7A1EC0079AFAF /* runtime */, 141211000A48772600480255 /* tests */, + 8603CEF014C753EF00AE59E3 /* tools */, 65162EF108E6A21C007556CD /* wtf */, 86EAC48C0F93E8B9008EC948 /* yarr */, 1C90513E0BA9E8830081E9D0 /* Configurations */, @@ -1678,6 +1730,8 @@ 1429D77A0ED20D7300B89619 /* interpreter */ = { isa = PBXGroup; children = ( + 0F55F0F114D1063600AC7649 /* AbstractPC.cpp */, + 0F55F0F214D1063600AC7649 /* AbstractPC.h */, A7F8690E0F9584A100558697 /* CachedCall.h */, 1429D8DB0ED2205B00B89619 /* CallFrame.cpp */, 1429D8DC0ED2205B00B89619 /* CallFrame.h */, @@ -1707,6 +1761,7 @@ 86CC85A20EE79B7400288682 /* JITCall.cpp */, 146FE51111A710430087AE66 /* JITCall32_64.cpp */, 86CCEFDD0F413F8900FD7F9E /* JITCode.h */, + 0F21C26614BE5F5E00ADC64B /* JITDriver.h */, 86CC85A00EE79A4700288682 /* JITInlineMethods.h */, BCDD51E90FB8DF74004A8BDC /* JITOpcodes.cpp */, A71236E41195F33C00BD2174 /* JITOpcodes32_64.cpp */, @@ -1727,8 +1782,10 @@ 142E312A134FF0A600AFADB5 /* heap */ = { isa = PBXGroup; children = ( - A70456AE1427FB030037DA68 /* AllocationSpace.cpp */, - A70456AF1427FB150037DA68 /* AllocationSpace.h */, + C2C8D02E14A3CEFC00578E65 /* BumpBlock.h */, + C240305314B404C90079EB64 /* BumpSpace.cpp */, + C2EAA3F8149A830800FCE112 /* BumpSpace.h */, + C2C8D02B14A3C6B200578E65 /* BumpSpaceInlineMethods.h */, A7521E121429169A003C8D0C /* CardSet.h */, 146B14DB12EB5B12001BEC1B /* ConservativeRoots.cpp */, 149DAAF212EB559D0083B12B /* ConservativeRoots.h */, @@ -1742,6 +1799,7 @@ 146FA5A81378F6B0003627A3 /* HandleTypes.h */, 14BA7A9513AADFF8005B7C2C /* Heap.cpp */, 14BA7A9613AADFF8005B7C2C /* Heap.h */, + C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */, 14F97446138C853E00DA1C67 /* HeapRootVisitor.h */, 0F431736146BAC65007E3890 /* ListableHandler.h */, 142E3130134FF0A600AFADB5 /* Local.h */, @@ -1777,7 +1835,6 @@ 865F408710E7D56300947361 /* APIShims.h */, 1CAA8B4A0D32C39A0041BCFF /* JavaScript.h */, 1CAA8B4B0D32C39A0041BCFF /* JavaScriptCore.h */, - 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */, BC0894D50FAFBA2D00001865 /* JSAPIValueWrapper.cpp */, BC0894D60FAFBA2D00001865 /* JSAPIValueWrapper.h */, 1421359A0A677F4F00A8195E /* JSBase.cpp */, @@ -1867,6 +1924,7 @@ 1C9051440BA9E8A70081E9D0 /* DebugRelease.xcconfig */, 449097EE0F8F81B50076A327 /* FeatureDefines.xcconfig */, 5DAFD6CB146B686300FBEFB4 /* JSC.xcconfig */, + 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */, BC021BF2136900C300FC5467 /* TestAPI.xcconfig */, 5DAFD6CC146B68B900FBEFB4 /* TestRegExp.xcconfig */, 1C9051420BA9E8A70081E9D0 /* Version.xcconfig */, @@ -2057,6 +2115,7 @@ A73BE165148420520091204B /* Uint16Array.h */, A73BE167148420520091204B /* Uint32Array.h */, A73BE163148420520091204B /* Uint8Array.h */, + 91A3905514C0F47200F67901 /* Uint8ClampedArray.h */, E195678D09E7CF1200B89D13 /* unicode */, 0FD52AAC1430359D0026DC9F /* UnionFind.h */, 935AF46B09E9D9DB00ACD1D8 /* UnusedParam.h */, @@ -2066,6 +2125,7 @@ 96DD73780F9DA3100027FBCC /* VMTags.h */, 86D08D5111793613006E5ED0 /* WTFThreadData.cpp */, 86D08D5211793613006E5ED0 /* WTFThreadData.h */, + C2D9CA1214BCC04600304B46 /* CheckedBoolean.h */, ); path = wtf; sourceTree = "<group>"; @@ -2314,6 +2374,19 @@ path = runtime; sourceTree = "<group>"; }; + 8603CEF014C753EF00AE59E3 /* tools */ = { + isa = PBXGroup; + children = ( + 86B5822E14D2373B00A9C306 /* CodeProfile.cpp */, + 86B5822F14D2373B00A9C306 /* CodeProfile.h */, + 8603CEF214C7546400AE59E3 /* CodeProfiling.cpp */, + 8603CEF314C7546400AE59E3 /* CodeProfiling.h */, + 86B5822C14D22F5F00A9C306 /* ProfileTreeNode.h */, + 86B5826A14D35D5100A9C306 /* TieredMMapArray.h */, + ); + path = tools; + sourceTree = "<group>"; + }; 8656573E115BE35200291F40 /* text */ = { isa = PBXGroup; children = ( @@ -2369,6 +2442,7 @@ 0F5F08CC146BE602000472A9 /* DFGByteCodeCache.h */, 86EC9DB41328DF82002B2AD7 /* DFGByteCodeParser.cpp */, 86EC9DB51328DF82002B2AD7 /* DFGByteCodeParser.h */, + 0F7B294814C3CD23007C3DB1 /* DFGCCallHelpers.h */, 0FD82E1E14172C2F00179C94 /* DFGCapabilities.cpp */, 0FD82E1F14172C2F00179C94 /* DFGCapabilities.h */, 0FC0977E1469EBC400CF2442 /* DFGCommon.h */, @@ -2405,7 +2479,6 @@ 86EC9DC31328DF82002B2AD7 /* DFGSpeculativeJIT.h */, 86880F1B14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp */, 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */, - 0FFF4BB2143955E600655BC0 /* DFGStructureSet.h */, 0FC0979F146B28C700CF2442 /* DFGThunks.cpp */, 0FC097A0146B28C700CF2442 /* DFGThunks.h */, 0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */, @@ -2474,6 +2547,15 @@ 969A078F0ED1D3AE00F1F681 /* bytecode */ = { isa = PBXGroup; children = ( + 0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */, + 0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */, + 0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */, + 0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */, + 0F93329714CA7DC10085F3C6 /* MethodCallLinkStatus.cpp */, + 0F93329814CA7DC10085F3C6 /* MethodCallLinkStatus.h */, + 0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */, + 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */, + 0F93329B14CA7DC10085F3C6 /* StructureSet.h */, 0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */, 0F0B83B614BCF8DF00885B4F /* GlobalResolveInfo.h */, 0F0B83B214BCF85E00885B4F /* MethodCallLinkInfo.cpp */, @@ -2586,7 +2668,6 @@ files = ( 860161E30F3A83C100F84710 /* AbstractMacroAssembler.h in Headers */, A1D764521354448B00C5C7C0 /* Alignment.h in Headers */, - A70456B01427FB910037DA68 /* AllocationSpace.h in Headers */, BC18C3E40E16F5CD00B34460 /* AlwaysInline.h in Headers */, BC18C3E50E16F5CD00B34460 /* APICast.h in Headers */, 865F408810E7D56300947361 /* APIShims.h in Headers */, @@ -2595,6 +2676,7 @@ 86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */, 86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */, A73BE169148420520091204B /* ArrayBuffer.h in Headers */, + C2D9CA1314BCC04600304B46 /* CheckedBoolean.h in Headers */, A73BE16B148420520091204B /* ArrayBufferView.h in Headers */, BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */, BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */, @@ -2621,7 +2703,10 @@ E4D8CEFB12FC439600BC9F5A /* BloomFilter.h in Headers */, BC18C3EC0E16F5CD00B34460 /* BooleanObject.h in Headers */, 0FD82E85141F3FE300179C94 /* BoundsCheckedPointer.h in Headers */, + C2C8D03014A3CEFC00578E65 /* BumpBlock.h in Headers */, 86676D5211FED9BC004B6863 /* BumpPointerAllocator.h in Headers */, + C2EAA3FA149A835E00FCE112 /* BumpSpace.h in Headers */, + C2C8D02D14A3C6E000578E65 /* BumpSpaceInlineMethods.h in Headers */, A7A1F7AD0F252B3C00E184E2 /* ByteArray.h in Headers */, 969A07230ED1CE3300F1F681 /* BytecodeGenerator.h in Headers */, C22C52F613FAF6EF00B7DC0D /* cached-powers.h in Headers */, @@ -2688,7 +2773,6 @@ 86BB09C1138E381B0056702F /* DFGRepatch.h in Headers */, 86ECA3FA132DF25A002B2AD7 /* DFGScoreBoard.h in Headers */, 86EC9DD31328DF82002B2AD7 /* DFGSpeculativeJIT.h in Headers */, - 0FFF4BB4143955E900655BC0 /* DFGStructureSet.h in Headers */, 0FC097A2146B28CC00CF2442 /* DFGThunks.h in Headers */, 0F620174143FCD330068B77C /* DFGVariableAccessData.h in Headers */, BC18C3FD0E16F5CD00B34460 /* DisallowCType.h in Headers */, @@ -2733,6 +2817,7 @@ BC18C40D0E16F5CD00B34460 /* HashTable.h in Headers */, BC18C40E0E16F5CD00B34460 /* HashTraits.h in Headers */, 14BA7A9813AADFF8005B7C2C /* Heap.h in Headers */, + C2C8D03114A3CEFC00578E65 /* HeapBlock.h in Headers */, 14F97447138C853E00DA1C67 /* HeapRootVisitor.h in Headers */, 7186A6EC13100BA5004479E1 /* HexNumber.h in Headers */, BC18C40F0E16F5CD00B34460 /* Identifier.h in Headers */, @@ -3021,6 +3106,19 @@ 0F0B83B514BCF86200885B4F /* MethodCallLinkInfo.h in Headers */, 0F0B83B714BCF8E100885B4F /* GlobalResolveInfo.h in Headers */, 0F0B83B914BCF95F00885B4F /* CallReturnOffsetToBytecodeOffset.h in Headers */, + 0F21C26814BE5F6800ADC64B /* JITDriver.h in Headers */, + 0F7B294A14C3CD29007C3DB1 /* DFGCCallHelpers.h in Headers */, + 0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */, + 0F7B294C14C3CD43007C3DB1 /* DFGByteCodeCache.h in Headers */, + 0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */, + 91A3905614C0F47200F67901 /* Uint8ClampedArray.h in Headers */, + F69E86C414C6E551002C2C62 /* NumberOfCores.h in Headers */, + 0F93329E14CA7DC50085F3C6 /* CallLinkStatus.h in Headers */, + 0F9332A014CA7DCD0085F3C6 /* GetByIdStatus.h in Headers */, + 0F9332A214CA7DD30085F3C6 /* MethodCallLinkStatus.h in Headers */, + 0F9332A414CA7DD90085F3C6 /* PutByIdStatus.h in Headers */, + 0F9332A514CA7DDD0085F3C6 /* StructureSet.h in Headers */, + 0F55F0F514D1063C00AC7649 /* AbstractPC.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3330,7 +3428,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A70456B11427FB950037DA68 /* AllocationSpace.cpp in Sources */, 147F39BD107EC37600427A48 /* ArgList.cpp in Sources */, 147F39BE107EC37600427A48 /* Arguments.cpp in Sources */, 86D3B2C310156BDE002865E7 /* ARMAssembler.cpp in Sources */, @@ -3348,6 +3445,7 @@ 14280863107EC11A0013E7B2 /* BooleanConstructor.cpp in Sources */, 14280864107EC11A0013E7B2 /* BooleanObject.cpp in Sources */, 14280865107EC11A0013E7B2 /* BooleanPrototype.cpp in Sources */, + C240305514B404E60079EB64 /* BumpSpace.cpp in Sources */, A7A1F7AC0F252B3C00E184E2 /* ByteArray.cpp in Sources */, 148F21AA107EC53A0042EC2C /* BytecodeGenerator.cpp in Sources */, C22C52F513FAF6EF00B7DC0D /* cached-powers.cc in Sources */, @@ -3558,6 +3656,14 @@ 0F46808314BA573100BFE272 /* JITExceptions.cpp in Sources */, 0F0B83B014BCF71600885B4F /* CallLinkInfo.cpp in Sources */, 0F0B83B414BCF86000885B4F /* MethodCallLinkInfo.cpp in Sources */, + F69E86C314C6E551002C2C62 /* NumberOfCores.cpp in Sources */, + 0F93329D14CA7DC30085F3C6 /* CallLinkStatus.cpp in Sources */, + 0F93329F14CA7DCA0085F3C6 /* GetByIdStatus.cpp in Sources */, + 0F9332A114CA7DD10085F3C6 /* MethodCallLinkStatus.cpp in Sources */, + 0F9332A314CA7DD70085F3C6 /* PutByIdStatus.cpp in Sources */, + 0F55F0F414D1063900AC7649 /* AbstractPC.cpp in Sources */, + 86B5826714D2796C00A9C306 /* CodeProfile.cpp in Sources */, + 86B5826914D2797000A9C306 /* CodeProfiling.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri index 6ea82d102..c61fb37f1 100644 --- a/Source/JavaScriptCore/Target.pri +++ b/Source/JavaScriptCore/Target.pri @@ -50,18 +50,22 @@ SOURCES += \ assembler/MacroAssemblerARM.cpp \ assembler/MacroAssemblerSH4.cpp \ bytecode/CallLinkInfo.cpp \ + bytecode/CallLinkStatus.cpp \ bytecode/CodeBlock.cpp \ bytecode/DFGExitProfile.cpp \ + bytecode/GetByIdStatus.cpp \ bytecode/JumpTable.cpp \ bytecode/MethodCallLinkInfo.cpp \ + bytecode/MethodCallLinkStatus.cpp \ bytecode/Opcode.cpp \ bytecode/PredictedType.cpp \ + bytecode/PutByIdStatus.cpp \ bytecode/SamplingTool.cpp \ bytecode/StructureStubInfo.cpp \ bytecode/ValueProfile.cpp \ bytecompiler/BytecodeGenerator.cpp \ bytecompiler/NodesCodegen.cpp \ - heap/AllocationSpace.cpp \ + heap/BumpSpace.cpp \ heap/ConservativeRoots.cpp \ heap/DFGCodeBlocks.cpp \ heap/HandleHeap.cpp \ @@ -96,6 +100,7 @@ SOURCES += \ dfg/DFGSpeculativeJIT32_64.cpp \ dfg/DFGSpeculativeJIT64.cpp \ dfg/DFGThunks.cpp \ + interpreter/AbstractPC.cpp \ interpreter/CallFrame.cpp \ interpreter/Interpreter.cpp \ interpreter/RegisterFile.cpp \ @@ -204,6 +209,8 @@ SOURCES += \ runtime/Structure.cpp \ runtime/TimeoutChecker.cpp \ runtime/UString.cpp \ + tools/CodeProfile.cpp \ + tools/CodeProfiling.cpp \ yarr/YarrJIT.cpp \ *sh4* { diff --git a/Source/JavaScriptCore/assembler/ARMAssembler.cpp b/Source/JavaScriptCore/assembler/ARMAssembler.cpp index 9e6c5e5fc..4ded0e88e 100644 --- a/Source/JavaScriptCore/assembler/ARMAssembler.cpp +++ b/Source/JavaScriptCore/assembler/ARMAssembler.cpp @@ -344,14 +344,14 @@ void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID b fdtr_u(isLoad, srcDst, ARMRegisters::S0, 0); } -PassRefPtr<ExecutableMemoryHandle> ARMAssembler::executableCopy(JSGlobalData& globalData) +PassRefPtr<ExecutableMemoryHandle> ARMAssembler::executableCopy(JSGlobalData& globalData, void* ownerUID) { // 64-bit alignment is required for next constant pool and JIT code as well m_buffer.flushWithoutBarrier(true); if (!m_buffer.isAligned(8)) bkpt(0); - RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(globalData); + RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(globalData, ownerUID); char* data = reinterpret_cast<char*>(result->start()); for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) { diff --git a/Source/JavaScriptCore/assembler/ARMAssembler.h b/Source/JavaScriptCore/assembler/ARMAssembler.h index 5792d2c0f..a659eefee 100644 --- a/Source/JavaScriptCore/assembler/ARMAssembler.h +++ b/Source/JavaScriptCore/assembler/ARMAssembler.h @@ -679,7 +679,7 @@ namespace JSC { return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool); } - PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData&); + PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData&, void* ownerUID); #ifndef NDEBUG unsigned debugOffset() { return m_buffer.debugOffset(); } diff --git a/Source/JavaScriptCore/assembler/ARMv7Assembler.h b/Source/JavaScriptCore/assembler/ARMv7Assembler.h index 530ae0d0b..0b83776df 100644 --- a/Source/JavaScriptCore/assembler/ARMv7Assembler.h +++ b/Source/JavaScriptCore/assembler/ARMv7Assembler.h @@ -414,11 +414,6 @@ private: class ARMv7Assembler { public: - ~ARMv7Assembler() - { - ASSERT(m_jumpsToLink.isEmpty()); - } - typedef ARMRegisters::RegisterID RegisterID; typedef ARMRegisters::FPSingleRegisterID FPSingleRegisterID; typedef ARMRegisters::FPDoubleRegisterID FPDoubleRegisterID; diff --git a/Source/JavaScriptCore/assembler/AssemblerBuffer.h b/Source/JavaScriptCore/assembler/AssemblerBuffer.h index 498dd09ac..c6e0a1003 100644 --- a/Source/JavaScriptCore/assembler/AssemblerBuffer.h +++ b/Source/JavaScriptCore/assembler/AssemblerBuffer.h @@ -129,12 +129,12 @@ namespace JSC { return AssemblerLabel(m_index); } - PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData) + PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID) { if (!m_index) return 0; - RefPtr<ExecutableMemoryHandle> result = globalData.executableAllocator.allocate(globalData, m_index); + RefPtr<ExecutableMemoryHandle> result = globalData.executableAllocator.allocate(globalData, m_index, ownerUID); if (!result) return 0; diff --git a/Source/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h b/Source/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h index 0287d4829..68afa766b 100644 --- a/Source/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h +++ b/Source/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h @@ -195,10 +195,10 @@ public: putIntegralUnchecked(value.low); } - PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData) + PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID) { flushConstantPool(false); - return AssemblerBuffer::executableCopy(globalData); + return AssemblerBuffer::executableCopy(globalData, ownerUID); } void putShortWithConstantInt(uint16_t insn, uint32_t constant, bool isReusable = false) diff --git a/Source/JavaScriptCore/assembler/LinkBuffer.h b/Source/JavaScriptCore/assembler/LinkBuffer.h index 1be8af217..e8047e100 100644 --- a/Source/JavaScriptCore/assembler/LinkBuffer.h +++ b/Source/JavaScriptCore/assembler/LinkBuffer.h @@ -31,6 +31,9 @@ #define DUMP_LINK_STATISTICS 0 #define DUMP_CODE 0 +#define GLOBAL_THUNK_ID reinterpret_cast<void*>(static_cast<intptr_t>(-1)) +#define REGEXP_CODE_ID reinterpret_cast<void*>(static_cast<intptr_t>(-2)) + #include <MacroAssembler.h> #include <wtf/Noncopyable.h> @@ -69,7 +72,7 @@ class LinkBuffer { #endif public: - LinkBuffer(JSGlobalData& globalData, MacroAssembler* masm) + LinkBuffer(JSGlobalData& globalData, MacroAssembler* masm, void* ownerUID) : m_size(0) , m_code(0) , m_assembler(masm) @@ -78,7 +81,7 @@ public: , m_completed(false) #endif { - linkCode(); + linkCode(ownerUID); } ~LinkBuffer() @@ -173,10 +176,7 @@ public: return applyOffset(label.m_label).m_offset; } - // Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called - // once to complete generation of the code. 'finalizeCode()' is suited to situations - // where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is - // suited to adding to an existing allocation. + // Upon completion of all patching 'finalizeCode()' should be called once to complete generation of the code. CodeRef finalizeCode() { performFinalization(); @@ -210,18 +210,17 @@ private: return src; } - // Keep this private! - the underlying code should only be obtained externally via - // finalizeCode() or finalizeCodeAddendum(). + // Keep this private! - the underlying code should only be obtained externally via finalizeCode(). void* code() { return m_code; } - void linkCode() + void linkCode(void* ownerUID) { ASSERT(!m_code); #if !ENABLE(BRANCH_COMPACTION) - m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData); + m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData, ownerUID); if (!m_executableMemory) return; m_code = m_executableMemory->start(); @@ -229,7 +228,7 @@ private: ASSERT(m_code); #else size_t initialSize = m_assembler->m_assembler.codeSize(); - m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, initialSize); + m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, initialSize, ownerUID); if (!m_executableMemory) return; m_code = (uint8_t*)m_executableMemory->start(); diff --git a/Source/JavaScriptCore/assembler/MIPSAssembler.h b/Source/JavaScriptCore/assembler/MIPSAssembler.h index da91a14f1..4471c1303 100644 --- a/Source/JavaScriptCore/assembler/MIPSAssembler.h +++ b/Source/JavaScriptCore/assembler/MIPSAssembler.h @@ -645,9 +645,9 @@ public: return m_buffer.codeSize(); } - PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData) + PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID) { - RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(globalData); + RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(globalData, ownerUID); if (!result) return 0; diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h b/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h index 82e8c4151..c59d1514a 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h @@ -52,7 +52,7 @@ #define ASSERT_VALID_CODE_OFFSET(offset) // Anything goes! #endif -#if CPU(X86) && OS(WIN) +#if CPU(X86) && OS(WINDOWS) #define CALLING_CONVENTION_IS_STDCALL 1 #ifndef CDECL #if COMPILER(MSVC) @@ -126,7 +126,9 @@ public: ASSERT_VALID_CODE_POINTER(m_value); } -#if CALLING_CONVENTION_IS_STDCALL +// MSVC doesn't seem to treat functions with different calling conventions as +// different types; these methods already defined for fastcall, below. +#if CALLING_CONVENTION_IS_STDCALL && !OS(WINDOWS) template<typename returnType> FunctionPtr(returnType (CDECL *value)()) diff --git a/Source/JavaScriptCore/assembler/SH4Assembler.h b/Source/JavaScriptCore/assembler/SH4Assembler.h index 90e232a63..0709588a5 100644 --- a/Source/JavaScriptCore/assembler/SH4Assembler.h +++ b/Source/JavaScriptCore/assembler/SH4Assembler.h @@ -1513,9 +1513,9 @@ public: return reinterpret_cast<void*>(readPCrelativeAddress((*instructionPtr & 0xff), instructionPtr)); } - PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData) + PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID) { - return m_buffer.executableCopy(globalData); + return m_buffer.executableCopy(globalData, ownerUID); } void prefix(uint16_t pre) diff --git a/Source/JavaScriptCore/assembler/X86Assembler.h b/Source/JavaScriptCore/assembler/X86Assembler.h index cd1921819..3b9e122cd 100644 --- a/Source/JavaScriptCore/assembler/X86Assembler.h +++ b/Source/JavaScriptCore/assembler/X86Assembler.h @@ -1782,9 +1782,9 @@ public: return b.m_offset - a.m_offset; } - PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData) + PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID) { - return m_formatter.executableCopy(globalData); + return m_formatter.executableCopy(globalData, ownerUID); } #ifndef NDEBUG @@ -2132,9 +2132,9 @@ private: bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } void* data() const { return m_buffer.data(); } - PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData) + PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID) { - return m_buffer.executableCopy(globalData); + return m_buffer.executableCopy(globalData, ownerUID); } #ifndef NDEBUG diff --git a/Source/JavaScriptCore/bytecode/CallLinkInfo.h b/Source/JavaScriptCore/bytecode/CallLinkInfo.h index 8ec48e4e1..44d50a971 100644 --- a/Source/JavaScriptCore/bytecode/CallLinkInfo.h +++ b/Source/JavaScriptCore/bytecode/CallLinkInfo.h @@ -72,7 +72,7 @@ struct CallLinkInfo : public BasicRawSentinelNode<CallLinkInfo> { WriteBarrier<JSFunction> lastSeenCallee; bool hasSeenShouldRepatch : 1; bool isDFG : 1; - CallType callType : 2; + CallType callType : 6; unsigned bytecodeIndex; bool isLinked() { return callee; } diff --git a/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp b/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp new file mode 100644 index 000000000..f3fd5bb27 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CallLinkStatus.h" + +#include "CodeBlock.h" + +namespace JSC { + +CallLinkStatus CallLinkStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex) +{ + UNUSED_PARAM(profiledBlock); + UNUSED_PARAM(bytecodeIndex); +#if ENABLE(JIT) && ENABLE(VALUE_PROFILER) + return CallLinkStatus( + profiledBlock->getCallLinkInfo(bytecodeIndex).lastSeenCallee.get(), + profiledBlock->couldTakeSlowCase(bytecodeIndex)); +#else + return CallLinkStatus(0, false); +#endif +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/bytecode/CallLinkStatus.h b/Source/JavaScriptCore/bytecode/CallLinkStatus.h new file mode 100644 index 000000000..e1c741016 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/CallLinkStatus.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 CallLinkStatus_h +#define CallLinkStatus_h + +namespace JSC { + +class JSFunction; +class CodeBlock; + +class CallLinkStatus { +public: + CallLinkStatus() + : m_callTarget(0) + , m_couldTakeSlowPath(false) + { + } + + CallLinkStatus(JSFunction* callTarget, bool couldTakeSlowPath) + : m_callTarget(callTarget) + , m_couldTakeSlowPath(couldTakeSlowPath) + { + } + + static CallLinkStatus computeFor(CodeBlock*, unsigned bytecodeIndex); + + bool isSet() const { return !!m_callTarget; } + + bool operator!() const { return !m_callTarget; } + + bool couldTakeSlowPath() const { return m_couldTakeSlowPath; } + + JSFunction* callTarget() const { return m_callTarget; } + +private: + JSFunction* m_callTarget; + bool m_couldTakeSlowPath; +}; + +} // namespace JSC + +#endif // CallLinkStatus_h + diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 47745268c..4a953266e 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -78,7 +78,7 @@ static UString valueToSourceString(ExecState* exec, JSValue val) return "0"; if (val.isString()) - return makeUString("\"", escapeQuotes(val.toString(exec)), "\""); + return makeUString("\"", escapeQuotes(val.toString(exec)->value(exec)), "\""); return val.description(); } @@ -180,7 +180,16 @@ void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); - it += 4; + it += 5; +} + +void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const +{ + int func = (++it)->u.operand; + int argCount = (++it)->u.operand; + int registerOffset = (++it)->u.operand; + printf("[%4d] %s\t %s, %d, %d\n", location, op, registerName(exec, func).data(), argCount, registerOffset); + it += 2; } void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const @@ -522,7 +531,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_convert_this: { int r0 = (++it)->u.operand; - printf("[%4d] convert_this %s\n", location, registerName(exec, r0).data()); + printf("[%4d] convert_this\t %s\n", location, registerName(exec, r0).data()); break; } case op_new_object: { @@ -734,6 +743,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; printf("[%4d] resolve\t\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); + it++; break; } case op_resolve_skip: { @@ -741,13 +751,14 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int id0 = (++it)->u.operand; int skipLevels = (++it)->u.operand; printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), skipLevels); + it++; break; } case op_resolve_global: { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; printf("[%4d] resolve_global\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); - it += 2; + it += 3; break; } case op_resolve_global_dynamic: { @@ -757,6 +768,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& ++it; int depth = (++it)->u.operand; printf("[%4d] resolve_global_dynamic\t %s, %s, %s, %d\n", location, registerName(exec, r0).data(), valueToSourceString(exec, scope).utf8().data(), idName(id0, m_identifiers[id0]).data(), depth); + ++it; break; } case op_get_scoped_var: { @@ -764,6 +776,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int index = (++it)->u.operand; int skipLevels = (++it)->u.operand; printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(exec, r0).data(), index, skipLevels); + it++; break; } case op_put_scoped_var: { @@ -777,6 +790,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; int index = (++it)->u.operand; printf("[%4d] get_global_var\t %s, %d\n", location, registerName(exec, r0).data(), index); + it++; break; } case op_put_global_var: { @@ -790,6 +804,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int id0 = (++it)->u.operand; int isStrict = (++it)->u.operand; printf("[%4d] resolve_base%s\t %s, %s\n", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); + it++; break; } case op_ensure_property_exists: { @@ -803,6 +818,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); + it++; break; } case op_resolve_with_this: { @@ -810,6 +826,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; printf("[%4d] resolve_with_this %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); + it++; break; } case op_get_by_id: { @@ -885,18 +902,12 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& printPutByIdOp(exec, location, it, "put_by_id_generic"); break; } - case op_put_getter: { + case op_put_getter_setter: { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data()); - break; - } - case op_put_setter: { - int r0 = (++it)->u.operand; - int id0 = (++it)->u.operand; - int r1 = (++it)->u.operand; - printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data()); + int r2 = (++it)->u.operand; + printf("[%4d] put_getter_setter\t %s, %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); break; } case op_method_check: { @@ -915,6 +926,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + it++; break; } case op_get_argument_by_val: { @@ -922,6 +934,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; printf("[%4d] get_argument_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + ++it; break; } case op_get_by_pname: { @@ -1119,17 +1132,11 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& break; } case op_call: { - int func = (++it)->u.operand; - int argCount = (++it)->u.operand; - int registerOffset = (++it)->u.operand; - printf("[%4d] call\t\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset); + printCallOp(exec, location, it, "call"); break; } case op_call_eval: { - int func = (++it)->u.operand; - int argCount = (++it)->u.operand; - int registerOffset = (++it)->u.operand; - printf("[%4d] call_eval\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset); + printCallOp(exec, location, it, "call_eval"); break; } case op_call_varargs: { @@ -1148,7 +1155,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_tear_off_arguments: { int r0 = (++it)->u.operand; - printf("[%4d] tear_off_arguments\t %s\n", location, registerName(exec, r0).data()); + printf("[%4d] tear_off_arguments %s\n", location, registerName(exec, r0).data()); break; } case op_ret: { @@ -1159,6 +1166,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& case op_call_put_result: { int r0 = (++it)->u.operand; printf("[%4d] op_call_put_result\t\t %s\n", location, registerName(exec, r0).data()); + it++; break; } case op_ret_object_or_this: { @@ -1168,10 +1176,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& break; } case op_construct: { - int func = (++it)->u.operand; - int argCount = (++it)->u.operand; - int registerOffset = (++it)->u.operand; - printf("[%4d] construct\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset); + printCallOp(exec, location, it, "construct"); break; } case op_strcat: { @@ -1446,6 +1451,9 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab) , m_speculativeFailCounter(0) , m_optimizationDelayCounter(0) , m_reoptimizationRetryCounter(0) +#if ENABLE(JIT) + , m_canCompileWithDFGState(CompileWithDFGUnset) +#endif { setNumParameters(other.numParameters()); optimizeAfterWarmUp(); @@ -2054,6 +2062,16 @@ void CodeBlock::createActivation(CallFrame* callFrame) callFrame->uncheckedR(activationRegister()) = JSValue(activation); callFrame->setScopeChain(callFrame->scopeChain()->push(activation)); } + +unsigned CodeBlock::addOrFindConstant(JSValue v) +{ + unsigned numberOfConstants = numberOfConstantRegisters(); + for (unsigned i = 0; i < numberOfConstants; ++i) { + if (getConstant(FirstConstantRegisterIndex + i) == v) + return i; + } + return addConstant(v); +} #if ENABLE(JIT) void CodeBlock::unlinkCalls() @@ -2154,17 +2172,17 @@ JSObject* FunctionCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* s return error; } -bool ProgramCodeBlock::canCompileWithDFG() +bool ProgramCodeBlock::canCompileWithDFGInternal() { return DFG::canCompileProgram(this); } -bool EvalCodeBlock::canCompileWithDFG() +bool EvalCodeBlock::canCompileWithDFGInternal() { return DFG::canCompileEval(this); } -bool FunctionCodeBlock::canCompileWithDFG() +bool FunctionCodeBlock::canCompileWithDFGInternal() { if (m_isConstructor) return DFG::canCompileFunctionForConstruct(this); diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index c440c72e1..23d6a6b6d 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -94,7 +94,7 @@ namespace JSC { Heap* m_heap; public: - virtual ~CodeBlock(); + JS_EXPORT_PRIVATE virtual ~CodeBlock(); int numParameters() const { return m_numParameters; } void setNumParameters(int newValue); @@ -388,7 +388,22 @@ namespace JSC { virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*) = 0; virtual void jettison() = 0; virtual CodeBlock* replacement() = 0; - virtual bool canCompileWithDFG() = 0; + + enum CompileWithDFGState { + CompileWithDFGFalse, + CompileWithDFGTrue, + CompileWithDFGUnset + }; + + virtual bool canCompileWithDFGInternal() = 0; + bool canCompileWithDFG() + { + bool result = canCompileWithDFGInternal(); + m_canCompileWithDFGState = result ? CompileWithDFGTrue : CompileWithDFGFalse; + return result; + } + CompileWithDFGState canCompileWithDFGState() { return m_canCompileWithDFGState; } + bool hasOptimizedReplacement() { ASSERT(getJITType() == JITCode::BaselineJIT); @@ -521,6 +536,11 @@ namespace JSC { { ValueProfile* result = WTF::genericBinarySearch<ValueProfile, int, getValueProfileBytecodeOffset>(m_valueProfiles, m_valueProfiles.size(), bytecodeOffset); ASSERT(result->m_bytecodeOffset != -1); + ASSERT(!hasInstructions() + || instructions()[bytecodeOffset + opcodeLength( + m_globalData->interpreter->getOpcodeID( + instructions()[ + bytecodeOffset].u.opcode)) - 1].u.profile == result); return result; } @@ -664,10 +684,22 @@ namespace JSC { return m_rareData && !!m_rareData->m_codeOrigins.size(); } - CodeOrigin codeOriginForReturn(ReturnAddressPtr returnAddress) + bool codeOriginForReturn(ReturnAddressPtr returnAddress, CodeOrigin& codeOrigin) { - ASSERT(hasCodeOrigins()); - return binarySearch<CodeOriginAtCallReturnOffset, unsigned, getCallReturnOffsetForCodeOrigin>(codeOrigins().begin(), codeOrigins().size(), getJITCode().offsetOf(returnAddress.value()))->codeOrigin; + if (!hasCodeOrigins()) + return false; + unsigned offset = getJITCode().offsetOf(returnAddress.value()); + CodeOriginAtCallReturnOffset* entry = binarySearch<CodeOriginAtCallReturnOffset, unsigned, getCallReturnOffsetForCodeOrigin>(codeOrigins().begin(), codeOrigins().size(), offset, WTF::KeyMustNotBePresentInArray); + if (entry->callReturnOffset != offset) + return false; + codeOrigin = entry->codeOrigin; + return true; + } + + CodeOrigin codeOrigin(unsigned index) + { + ASSERT(m_rareData); + return m_rareData->m_codeOrigins[index].codeOrigin; } bool addFrequentExitSite(const DFG::FrequentExitSite& site) @@ -686,11 +718,14 @@ namespace JSC { Identifier& identifier(int index) { return m_identifiers[index]; } size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } - void addConstant(JSValue v) + unsigned addConstant(JSValue v) { + unsigned result = m_constantRegisters.size(); m_constantRegisters.append(WriteBarrier<Unknown>()); m_constantRegisters.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), v); + return result; } + unsigned addOrFindConstant(JSValue); WriteBarrier<Unknown>& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; } ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); } @@ -780,7 +815,7 @@ namespace JSC { // Functions for controlling when tiered compilation kicks in. This // controls both when the optimizing compiler is invoked and when OSR // entry happens. Two triggers exist: the loop trigger and the return - // trigger. In either case, when an addition to m_executeCounter + // trigger. In either case, when an addition to m_jitExecuteCounter // causes it to become non-negative, the optimizing compiler is // invoked. This includes a fast check to see if this CodeBlock has // already been optimized (i.e. replacement() returns a CodeBlock @@ -821,14 +856,14 @@ namespace JSC { return Options::executionCounterValueForOptimizeAfterLongWarmUp << reoptimizationRetryCounter(); } - int32_t* addressOfExecuteCounter() + int32_t* addressOfJITExecuteCounter() { - return &m_executeCounter; + return &m_jitExecuteCounter; } - static ptrdiff_t offsetOfExecuteCounter() { return OBJECT_OFFSETOF(CodeBlock, m_executeCounter); } + static ptrdiff_t offsetOfJITExecuteCounter() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter); } - int32_t executeCounter() const { return m_executeCounter; } + int32_t jitExecuteCounter() const { return m_jitExecuteCounter; } unsigned optimizationDelayCounter() const { return m_optimizationDelayCounter; } @@ -837,7 +872,7 @@ namespace JSC { // expensive than executing baseline code. void optimizeNextInvocation() { - m_executeCounter = Options::executionCounterValueForOptimizeNextInvocation; + m_jitExecuteCounter = Options::executionCounterValueForOptimizeNextInvocation; } // Call this to prevent optimization from happening again. Note that @@ -847,7 +882,7 @@ namespace JSC { // the future as well. void dontOptimizeAnytimeSoon() { - m_executeCounter = Options::executionCounterValueForDontOptimizeAnytimeSoon; + m_jitExecuteCounter = Options::executionCounterValueForDontOptimizeAnytimeSoon; } // Call this to reinitialize the counter to its starting state, @@ -858,14 +893,14 @@ namespace JSC { // counter that this corresponds to is also available directly. void optimizeAfterWarmUp() { - m_executeCounter = counterValueForOptimizeAfterWarmUp(); + m_jitExecuteCounter = counterValueForOptimizeAfterWarmUp(); } // Call this to force an optimization trigger to fire only after // a lot of warm-up. void optimizeAfterLongWarmUp() { - m_executeCounter = counterValueForOptimizeAfterLongWarmUp(); + m_jitExecuteCounter = counterValueForOptimizeAfterLongWarmUp(); } // Call this to cause an optimization trigger to fire soon, but @@ -888,7 +923,7 @@ namespace JSC { // in the baseline code. void optimizeSoon() { - m_executeCounter = Options::executionCounterValueForOptimizeSoon << reoptimizationRetryCounter(); + m_jitExecuteCounter = Options::executionCounterValueForOptimizeSoon << reoptimizationRetryCounter(); } // The speculative JIT tracks its success rate, so that we can @@ -989,6 +1024,7 @@ namespace JSC { void printBinaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; void printConditionalJump(ExecState*, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator&, int location, const char* op) const; void printGetByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; + void printCallOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; void printPutByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; #endif void visitStructures(SlotVisitor&, Instruction* vPC) const; @@ -1129,7 +1165,7 @@ namespace JSC { OwnPtr<CodeBlock> m_alternative; - int32_t m_executeCounter; + int32_t m_jitExecuteCounter; uint32_t m_speculativeSuccessCounter; uint32_t m_speculativeFailCounter; uint8_t m_optimizationDelayCounter; @@ -1169,6 +1205,9 @@ namespace JSC { friend void WTF::deleteOwnedPtr<RareData>(RareData*); #endif OwnPtr<RareData> m_rareData; +#if ENABLE(JIT) + CompileWithDFGState m_canCompileWithDFGState; +#endif }; // Program code is not marked by any function, so we make the global object @@ -1208,7 +1247,7 @@ namespace JSC { virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); virtual void jettison(); virtual CodeBlock* replacement(); - virtual bool canCompileWithDFG(); + virtual bool canCompileWithDFGInternal(); #endif }; @@ -1242,7 +1281,7 @@ namespace JSC { virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); virtual void jettison(); virtual CodeBlock* replacement(); - virtual bool canCompileWithDFG(); + virtual bool canCompileWithDFGInternal(); #endif private: @@ -1279,7 +1318,7 @@ namespace JSC { virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); virtual void jettison(); virtual CodeBlock* replacement(); - virtual bool canCompileWithDFG(); + virtual bool canCompileWithDFGInternal(); #endif }; diff --git a/Source/JavaScriptCore/bytecode/CodeOrigin.h b/Source/JavaScriptCore/bytecode/CodeOrigin.h index 7b6ce7d48..25a116c55 100644 --- a/Source/JavaScriptCore/bytecode/CodeOrigin.h +++ b/Source/JavaScriptCore/bytecode/CodeOrigin.h @@ -38,29 +38,37 @@ class ExecutableBase; class JSFunction; struct CodeOrigin { - uint32_t bytecodeIndex; + // Bytecode offset that you'd use to re-execute this instruction. + unsigned bytecodeIndex : 29; + // Bytecode offset corresponding to the opcode that gives the result (needed to handle + // op_call/op_call_put_result and op_method_check/op_get_by_id). + unsigned valueProfileOffset : 3; + InlineCallFrame* inlineCallFrame; CodeOrigin() : bytecodeIndex(std::numeric_limits<uint32_t>::max()) + , valueProfileOffset(0) , inlineCallFrame(0) { } - explicit CodeOrigin(uint32_t bytecodeIndex) - : bytecodeIndex(bytecodeIndex) - , inlineCallFrame(0) - { - } - - explicit CodeOrigin(uint32_t bytecodeIndex, InlineCallFrame* inlineCallFrame) + explicit CodeOrigin(unsigned bytecodeIndex, InlineCallFrame* inlineCallFrame = 0, unsigned valueProfileOffset = 0) : bytecodeIndex(bytecodeIndex) + , valueProfileOffset(valueProfileOffset) , inlineCallFrame(inlineCallFrame) { + ASSERT(bytecodeIndex < (1u << 29)); + ASSERT(valueProfileOffset < (1u << 3)); } bool isSet() const { return bytecodeIndex != std::numeric_limits<uint32_t>::max(); } + unsigned bytecodeIndexForValueProfile() const + { + return bytecodeIndex + valueProfileOffset; + } + // The inline depth is the depth of the inline stack, so 1 = not inlined, // 2 = inlined one deep, etc. unsigned inlineDepth() const; diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp new file mode 100644 index 000000000..5eff1d4a0 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GetByIdStatus.h" + +#include "CodeBlock.h" + +namespace JSC { + +GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident) +{ + UNUSED_PARAM(profiledBlock); + UNUSED_PARAM(bytecodeIndex); + UNUSED_PARAM(ident); +#if ENABLE(JIT) && ENABLE(VALUE_PROFILER) + // First check if it makes either calls, in which case we want to be super careful, or + // if it's not set at all, in which case we punt. + StructureStubInfo& stubInfo = profiledBlock->getStubInfo(bytecodeIndex); + if (!stubInfo.seen) + return GetByIdStatus(NoInformation, StructureSet(), notFound); + + PolymorphicAccessStructureList* list; + int listSize; + switch (stubInfo.accessType) { + case access_get_by_id_self_list: + list = stubInfo.u.getByIdSelfList.structureList; + listSize = stubInfo.u.getByIdSelfList.listSize; + break; + case access_get_by_id_proto_list: + list = stubInfo.u.getByIdProtoList.structureList; + listSize = stubInfo.u.getByIdProtoList.listSize; + break; + default: + list = 0; + listSize = 0; + break; + } + for (int i = 0; i < listSize; ++i) { + if (!list->list[i].isDirect) + return GetByIdStatus(MakesCalls, StructureSet(), notFound); + } + + // Next check if it takes slow case, in which case we want to be kind of careful. + if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex)) + return GetByIdStatus(TakesSlowPath, StructureSet(), notFound); + + // Finally figure out if we can derive an access strategy. + GetByIdStatus result; + switch (stubInfo.accessType) { + case access_unset: + return GetByIdStatus(NoInformation, StructureSet(), notFound); + + case access_get_by_id_self: { + Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get(); + result.m_offset = structure->get(*profiledBlock->globalData(), ident); + + if (result.m_offset != notFound) + result.m_structureSet.add(structure); + + if (result.m_offset != notFound) + ASSERT(result.m_structureSet.size()); + break; + } + + case access_get_by_id_self_list: { + PolymorphicAccessStructureList* list = stubInfo.u.getByIdProtoList.structureList; + unsigned size = stubInfo.u.getByIdProtoList.listSize; + for (unsigned i = 0; i < size; ++i) { + ASSERT(list->list[i].isDirect); + + Structure* structure = list->list[i].base.get(); + if (result.m_structureSet.contains(structure)) + continue; + + size_t myOffset = structure->get(*profiledBlock->globalData(), ident); + + if (myOffset == notFound) { + result.m_offset = notFound; + break; + } + + if (!i) + result.m_offset = myOffset; + else if (result.m_offset != myOffset) { + result.m_offset = notFound; + break; + } + + result.m_structureSet.add(structure); + } + + if (result.m_offset != notFound) + ASSERT(result.m_structureSet.size()); + break; + } + + default: + ASSERT(result.m_offset == notFound); + break; + } + + if (result.m_offset == notFound) { + result.m_state = TakesSlowPath; + result.m_structureSet.clear(); + } else + result.m_state = SimpleDirect; + + return result; +#else // ENABLE(JIT) + return GetByIdStatus(NoInformation, StructureSet(), notFound); +#endif // ENABLE(JIT) +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.h b/Source/JavaScriptCore/bytecode/GetByIdStatus.h new file mode 100644 index 000000000..00e50e76d --- /dev/null +++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 GetByIdStatus_h +#define GetByIdStatus_h + +#include "StructureSet.h" +#include <wtf/NotFound.h> + +namespace JSC { + +class CodeBlock; +class Identifier; + +class GetByIdStatus { +public: + enum State { + NoInformation, // It's uncached so we have no information. + SimpleDirect, // It's cached for a direct access to a known object property. + TakesSlowPath, // It's known to often take slow path. + MakesCalls // It's known to take paths that make calls. + }; + + GetByIdStatus() + : m_state(NoInformation) + , m_offset(notFound) + { + } + + GetByIdStatus(State state, const StructureSet& structureSet, size_t offset) + : m_state(state) + , m_structureSet(structureSet) + , m_offset(offset) + { + ASSERT((state == SimpleDirect) == (offset != notFound)); + } + + static GetByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&); + + State state() const { return m_state; } + + bool isSet() const { return m_state != NoInformation; } + bool operator!() const { return !isSet(); } + bool isSimpleDirect() const { return m_state == SimpleDirect; } + bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; } + bool makesCalls() const { return m_state == MakesCalls; } + + const StructureSet& structureSet() const { return m_structureSet; } + size_t offset() const { return m_offset; } + +private: + State m_state; + StructureSet m_structureSet; + size_t m_offset; +}; + +} // namespace JSC + +#endif // PropertyAccessStatus_h + diff --git a/Source/JavaScriptCore/bytecode/Instruction.h b/Source/JavaScriptCore/bytecode/Instruction.h index 7e4413065..92118eeb2 100644 --- a/Source/JavaScriptCore/bytecode/Instruction.h +++ b/Source/JavaScriptCore/bytecode/Instruction.h @@ -48,6 +48,7 @@ namespace JSC { class JSCell; class Structure; class StructureChain; + struct ValueProfile; #if ENABLE(JIT) typedef MacroAssemblerCodeRef PolymorphicAccessStructureListStubRoutineType; @@ -99,6 +100,10 @@ namespace JSC { } } list[POLYMORPHIC_LIST_CACHE_SIZE]; + PolymorphicAccessStructureList() + { + } + PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, bool isDirect) { list[0].set(globalData, owner, stubRoutine, firstBase, isDirect); @@ -176,6 +181,8 @@ namespace JSC { } Instruction(PropertySlot::GetValueFunc getterFunc) { u.getterFunc = getterFunc; } + + Instruction(ValueProfile* profile) { u.profile = profile; } union { Opcode opcode; @@ -184,6 +191,7 @@ namespace JSC { WriteBarrierBase<StructureChain> structureChain; WriteBarrierBase<JSCell> jsCell; PropertySlot::GetValueFunc getterFunc; + ValueProfile* profile; } u; private: diff --git a/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp b/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp new file mode 100644 index 000000000..e7d721c29 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "MethodCallLinkStatus.h" + +#include "CodeBlock.h" + +namespace JSC { + +MethodCallLinkStatus MethodCallLinkStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex) +{ + UNUSED_PARAM(profiledBlock); + UNUSED_PARAM(bytecodeIndex); +#if ENABLE(JIT) && ENABLE(VALUE_PROFILER) + MethodCallLinkInfo& methodCall = profiledBlock->getMethodCallLinkInfo(bytecodeIndex); + + if (!methodCall.seen || !methodCall.cachedStructure) + return MethodCallLinkStatus(); + + if (methodCall.cachedPrototype.get() == profiledBlock->globalObject()->methodCallDummy()) { + return MethodCallLinkStatus( + methodCall.cachedStructure.get(), + 0, + methodCall.cachedFunction.get(), + 0); + } + + return MethodCallLinkStatus( + methodCall.cachedStructure.get(), + methodCall.cachedPrototypeStructure.get(), + methodCall.cachedFunction.get(), + methodCall.cachedPrototype.get()); +#else // ENABLE(JIT) + return MethodCallLinkStatus(); +#endif // ENABLE(JIT) +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h b/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h new file mode 100644 index 000000000..c3d11a1d8 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 MethodCallLinkStatus_h +#define MethodCallLinkStatus_h + +namespace JSC { + +class CodeBlock; +class JSObject; +class Structure; + +class MethodCallLinkStatus { +public: + MethodCallLinkStatus() + : m_structure(0) + , m_prototypeStructure(0) + , m_function(0) + , m_prototype(0) + { + } + + MethodCallLinkStatus( + Structure* structure, + Structure* prototypeStructure, + JSObject* function, + JSObject* prototype) + : m_structure(structure) + , m_prototypeStructure(prototypeStructure) + , m_function(function) + , m_prototype(prototype) + { + if (!m_function) { + ASSERT(!m_structure); + ASSERT(!m_prototypeStructure); + ASSERT(!m_prototype); + } else + ASSERT(m_structure); + + ASSERT(!m_prototype == !m_prototypeStructure); + } + + static MethodCallLinkStatus computeFor(CodeBlock*, unsigned bytecodeIndex); + + bool isSet() const { return !!m_function; } + bool operator!() const { return !m_function; } + + bool needsPrototypeCheck() const { return !!m_prototype; } + + Structure* structure() { return m_structure; } + Structure* prototypeStructure() { return m_prototypeStructure; } + JSObject* function() const { return m_function; } + JSObject* prototype() const { return m_prototype; } + +private: + Structure* m_structure; + Structure* m_prototypeStructure; + JSObject* m_function; + JSObject* m_prototype; +}; + +} // namespace JSC + +#endif // MethodCallLinkStatus_h + diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index 4801e4c32..57633a338 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -95,45 +95,44 @@ namespace JSC { macro(op_is_function, 3) \ macro(op_in, 4) \ \ - macro(op_resolve, 3) \ - macro(op_resolve_skip, 4) \ - macro(op_resolve_global, 5) \ - macro(op_resolve_global_dynamic, 6) \ - macro(op_get_scoped_var, 4) \ + macro(op_resolve, 4) /* has value profiling */ \ + macro(op_resolve_skip, 5) /* has value profiling */ \ + macro(op_resolve_global, 6) /* has value profiling */ \ + macro(op_resolve_global_dynamic, 7) /* has value profiling */ \ + macro(op_get_scoped_var, 5) /* has value profiling */ \ macro(op_put_scoped_var, 4) \ - macro(op_get_global_var, 3) \ + macro(op_get_global_var, 4) /* has value profiling */ \ macro(op_put_global_var, 3) \ - macro(op_resolve_base, 4) \ + macro(op_resolve_base, 5) /* has value profiling */ \ macro(op_ensure_property_exists, 3) \ - macro(op_resolve_with_base, 4) \ - macro(op_resolve_with_this, 4) \ - macro(op_get_by_id, 8) \ - macro(op_get_by_id_self, 8) \ - macro(op_get_by_id_proto, 8) \ - macro(op_get_by_id_chain, 8) \ - macro(op_get_by_id_getter_self, 8) \ - macro(op_get_by_id_getter_proto, 8) \ - macro(op_get_by_id_getter_chain, 8) \ - macro(op_get_by_id_custom_self, 8) \ - macro(op_get_by_id_custom_proto, 8) \ - macro(op_get_by_id_custom_chain, 8) \ - macro(op_get_by_id_generic, 8) \ - macro(op_get_array_length, 8) \ - macro(op_get_string_length, 8) \ + macro(op_resolve_with_base, 5) /* has value profiling */ \ + macro(op_resolve_with_this, 5) /* has value profiling */ \ + macro(op_get_by_id, 9) /* has value profiling */ \ + macro(op_get_by_id_self, 9) /* has value profiling */ \ + macro(op_get_by_id_proto, 9) /* has value profiling */ \ + macro(op_get_by_id_chain, 9) /* has value profiling */ \ + macro(op_get_by_id_getter_self, 9) /* has value profiling */ \ + macro(op_get_by_id_getter_proto, 9) /* has value profiling */ \ + macro(op_get_by_id_getter_chain, 9) /* has value profiling */ \ + macro(op_get_by_id_custom_self, 9) /* has value profiling */ \ + macro(op_get_by_id_custom_proto, 9) /* has value profiling */ \ + macro(op_get_by_id_custom_chain, 9) /* has value profiling */ \ + macro(op_get_by_id_generic, 9) /* has value profiling */ \ + macro(op_get_array_length, 9) /* has value profiling */ \ + macro(op_get_string_length, 9) /* has value profiling */ \ macro(op_get_arguments_length, 4) \ macro(op_put_by_id, 9) \ macro(op_put_by_id_transition, 9) \ macro(op_put_by_id_replace, 9) \ macro(op_put_by_id_generic, 9) \ macro(op_del_by_id, 4) \ - macro(op_get_by_val, 4) \ - macro(op_get_argument_by_val, 4) \ + macro(op_get_by_val, 5) /* has value profiling */ \ + macro(op_get_argument_by_val, 5) /* must be the same size as op_get_by_val */ \ macro(op_get_by_pname, 7) \ macro(op_put_by_val, 4) \ macro(op_del_by_val, 4) \ macro(op_put_by_index, 4) \ - macro(op_put_getter, 4) \ - macro(op_put_setter, 4) \ + macro(op_put_getter_setter, 5) \ \ macro(op_jmp, 2) \ macro(op_jtrue, 3) \ @@ -170,7 +169,7 @@ namespace JSC { macro(op_tear_off_activation, 3) \ macro(op_tear_off_arguments, 2) \ macro(op_ret, 2) \ - macro(op_call_put_result, 2) \ + macro(op_call_put_result, 3) /* has value profiling */ \ macro(op_ret_object_or_this, 3) \ macro(op_method_check, 1) \ \ diff --git a/Source/JavaScriptCore/bytecode/PredictedType.cpp b/Source/JavaScriptCore/bytecode/PredictedType.cpp index 9356390a9..4b07ff446 100644 --- a/Source/JavaScriptCore/bytecode/PredictedType.cpp +++ b/Source/JavaScriptCore/bytecode/PredictedType.cpp @@ -92,6 +92,11 @@ const char* predictionToString(PredictedType value) ptr.strcat("Uint8array"); else isTop = false; + + if (value & PredictUint8ClampedArray) + ptr.strcat("Uint8clampedarray"); + else + isTop = false; if (value & PredictUint16Array) ptr.strcat("Uint16array"); @@ -184,6 +189,8 @@ PredictedType predictionFromClassInfo(const ClassInfo* classInfo) return PredictInt32Array; case TypedArrayUint8: return PredictUint8Array; + case TypedArrayUint8Clamped: + return PredictUint8ClampedArray; case TypedArrayUint16: return PredictUint16Array; case TypedArrayUint32: diff --git a/Source/JavaScriptCore/bytecode/PredictedType.h b/Source/JavaScriptCore/bytecode/PredictedType.h index 3ec03924a..47583361d 100644 --- a/Source/JavaScriptCore/bytecode/PredictedType.h +++ b/Source/JavaScriptCore/bytecode/PredictedType.h @@ -36,33 +36,34 @@ namespace JSC { class Structure; typedef uint32_t PredictedType; -static const PredictedType PredictNone = 0x00000000; // We don't know anything yet. -static const PredictedType PredictFinalObject = 0x00000001; // It's definitely a JSFinalObject. -static const PredictedType PredictArray = 0x00000002; // It's definitely a JSArray. -static const PredictedType PredictByteArray = 0x00000004; // It's definitely a JSByteArray or one of its subclasses. -static const PredictedType PredictFunction = 0x00000008; // It's definitely a JSFunction or one of its subclasses. -static const PredictedType PredictInt8Array = 0x00000010; // It's definitely an Int8Array or one of its subclasses. -static const PredictedType PredictInt16Array = 0x00000020; // It's definitely an Int16Array or one of its subclasses. -static const PredictedType PredictInt32Array = 0x00000040; // It's definitely an Int32Array or one of its subclasses. -static const PredictedType PredictUint8Array = 0x00000080; // It's definitely an Uint8Array or one of its subclasses. -static const PredictedType PredictUint16Array = 0x00000100; // It's definitely an Uint16Array or one of its subclasses. -static const PredictedType PredictUint32Array = 0x00000200; // It's definitely an Uint32Array or one of its subclasses. -static const PredictedType PredictFloat32Array = 0x00000400; // It's definitely an Uint16Array or one of its subclasses. -static const PredictedType PredictFloat64Array = 0x00000800; // It's definitely an Uint16Array or one of its subclasses. -static const PredictedType PredictObjectOther = 0x00001000; // It's definitely an object but not JSFinalObject, JSArray, JSByteArray, or JSFunction. -static const PredictedType PredictObjectMask = 0x00001fff; // Bitmask used for testing for any kind of object prediction. -static const PredictedType PredictString = 0x00002000; // It's definitely a JSString. -static const PredictedType PredictCellOther = 0x00004000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString. -static const PredictedType PredictCell = 0x00007fff; // It's definitely a JSCell. -static const PredictedType PredictInt32 = 0x00008000; // It's definitely an Int32. -static const PredictedType PredictDoubleReal = 0x00010000; // It's definitely a non-NaN double. -static const PredictedType PredictDoubleNaN = 0x00020000; // It's definitely a NaN. -static const PredictedType PredictDouble = 0x00030000; // It's either a non-NaN or a NaN double. -static const PredictedType PredictNumber = 0x00038000; // It's either an Int32 or a Double. -static const PredictedType PredictBoolean = 0x00040000; // It's definitely a Boolean. -static const PredictedType PredictOther = 0x40000000; // It's definitely none of the above. -static const PredictedType PredictTop = 0x7fffffff; // It can be any of the above. -static const PredictedType FixedIndexedStorageMask = PredictByteArray | PredictInt8Array | PredictInt16Array | PredictInt32Array | PredictUint8Array | PredictUint16Array | PredictUint32Array | PredictFloat32Array | PredictFloat64Array; +static const PredictedType PredictNone = 0x00000000; // We don't know anything yet. +static const PredictedType PredictFinalObject = 0x00000001; // It's definitely a JSFinalObject. +static const PredictedType PredictArray = 0x00000002; // It's definitely a JSArray. +static const PredictedType PredictByteArray = 0x00000004; // It's definitely a JSByteArray or one of its subclasses. +static const PredictedType PredictFunction = 0x00000008; // It's definitely a JSFunction or one of its subclasses. +static const PredictedType PredictInt8Array = 0x00000010; // It's definitely an Int8Array or one of its subclasses. +static const PredictedType PredictInt16Array = 0x00000020; // It's definitely an Int16Array or one of its subclasses. +static const PredictedType PredictInt32Array = 0x00000040; // It's definitely an Int32Array or one of its subclasses. +static const PredictedType PredictUint8Array = 0x00000080; // It's definitely an Uint8Array or one of its subclasses. +static const PredictedType PredictUint8ClampedArray = 0x00000100; // It's definitely an Uint8ClampedArray or one of its subclasses. +static const PredictedType PredictUint16Array = 0x00000200; // It's definitely an Uint16Array or one of its subclasses. +static const PredictedType PredictUint32Array = 0x00000400; // It's definitely an Uint32Array or one of its subclasses. +static const PredictedType PredictFloat32Array = 0x00000800; // It's definitely an Uint16Array or one of its subclasses. +static const PredictedType PredictFloat64Array = 0x00001000; // It's definitely an Uint16Array or one of its subclasses. +static const PredictedType PredictObjectOther = 0x00002000; // It's definitely an object but not JSFinalObject, JSArray, JSByteArray, or JSFunction. +static const PredictedType PredictObjectMask = 0x00003fff; // Bitmask used for testing for any kind of object prediction. +static const PredictedType PredictString = 0x00004000; // It's definitely a JSString. +static const PredictedType PredictCellOther = 0x00008000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString. +static const PredictedType PredictCell = 0x0000ffff; // It's definitely a JSCell. +static const PredictedType PredictInt32 = 0x00010000; // It's definitely an Int32. +static const PredictedType PredictDoubleReal = 0x00020000; // It's definitely a non-NaN double. +static const PredictedType PredictDoubleNaN = 0x00040000; // It's definitely a NaN. +static const PredictedType PredictDouble = 0x00060000; // It's either a non-NaN or a NaN double. +static const PredictedType PredictNumber = 0x00070000; // It's either an Int32 or a Double. +static const PredictedType PredictBoolean = 0x00080000; // It's definitely a Boolean. +static const PredictedType PredictOther = 0x40000000; // It's definitely none of the above. +static const PredictedType PredictTop = 0x7fffffff; // It can be any of the above. +static const PredictedType FixedIndexedStorageMask = PredictByteArray | PredictInt8Array | PredictInt16Array | PredictInt32Array | PredictUint8Array | PredictUint8ClampedArray | PredictUint16Array | PredictUint32Array | PredictFloat32Array | PredictFloat64Array; typedef bool (*PredictionChecker)(PredictedType); @@ -131,6 +132,11 @@ inline bool isUint8ArrayPrediction(PredictedType value) return value == PredictUint8Array; } +inline bool isUint8ClampedArrayPrediction(PredictedType value) +{ + return value == PredictUint8ClampedArray; +} + inline bool isUint16ArrayPrediction(PredictedType value) { return value == PredictUint16Array; @@ -161,6 +167,7 @@ inline bool isActionableMutableArrayPrediction(PredictedType value) #endif || isInt32ArrayPrediction(value) || isUint8ArrayPrediction(value) + || isUint8ClampedArrayPrediction(value) || isUint16ArrayPrediction(value) || isUint32ArrayPrediction(value) #if CPU(X86) || CPU(X86_64) diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp new file mode 100644 index 000000000..45a5e614c --- /dev/null +++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PutByIdStatus.h" + +#include "CodeBlock.h" +#include "Structure.h" +#include "StructureChain.h" + +namespace JSC { + +PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident) +{ + UNUSED_PARAM(profiledBlock); + UNUSED_PARAM(bytecodeIndex); + UNUSED_PARAM(ident); +#if ENABLE(JIT) && ENABLE(VALUE_PROFILER) + if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex)) + return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound); + + StructureStubInfo& stubInfo = profiledBlock->getStubInfo(bytecodeIndex); + if (!stubInfo.seen) + return PutByIdStatus(NoInformation, 0, 0, 0, notFound); + + switch (stubInfo.accessType) { + case access_unset: + return PutByIdStatus(NoInformation, 0, 0, 0, notFound); + + case access_put_by_id_replace: { + size_t offset = stubInfo.u.putByIdReplace.baseObjectStructure->get( + *profiledBlock->globalData(), ident); + if (offset != notFound) { + return PutByIdStatus( + SimpleReplace, + stubInfo.u.putByIdReplace.baseObjectStructure.get(), + 0, 0, + offset); + } + return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound); + } + + case access_put_by_id_transition_normal: + case access_put_by_id_transition_direct: { + size_t offset = stubInfo.u.putByIdTransition.structure->get( + *profiledBlock->globalData(), ident); + if (offset != notFound) { + return PutByIdStatus( + SimpleTransition, + stubInfo.u.putByIdTransition.previousStructure.get(), + stubInfo.u.putByIdTransition.structure.get(), + stubInfo.u.putByIdTransition.chain.get(), + offset); + } + return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound); + } + + default: + return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound); + } +#else // ENABLE(JIT) + return PutByIdStatus(NoInformation, 0, 0, 0, notFound); +#endif // ENABLE(JIT) +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.h b/Source/JavaScriptCore/bytecode/PutByIdStatus.h new file mode 100644 index 000000000..b33f4d09c --- /dev/null +++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 PutByIdStatus_h +#define PutByIdStatus_h + +#include <wtf/NotFound.h> + +namespace JSC { + +class CodeBlock; +class Identifier; +class Structure; +class StructureChain; + +class PutByIdStatus { +public: + enum State { + // It's uncached so we have no information. + NoInformation, + // It's cached as a direct store into an object property for cases where the object + // already has the property. + SimpleReplace, + // It's cached as a transition from one structure that lacks the property to one that + // includes the property, and a direct store to this new property. + SimpleTransition, + // It's known to often take slow path. + TakesSlowPath + }; + + PutByIdStatus() + : m_state(NoInformation) + , m_oldStructure(0) + , m_newStructure(0) + , m_structureChain(0) + , m_offset(notFound) + { + } + + PutByIdStatus( + State state, + Structure* oldStructure, + Structure* newStructure, + StructureChain* structureChain, + size_t offset) + : m_state(state) + , m_oldStructure(oldStructure) + , m_newStructure(newStructure) + , m_structureChain(structureChain) + , m_offset(offset) + { + ASSERT((m_state == NoInformation || m_state == TakesSlowPath) == !m_oldStructure); + ASSERT((m_state != SimpleTransition) == !m_newStructure); + ASSERT((m_state != SimpleTransition) == !m_structureChain); + ASSERT((m_state == NoInformation || m_state == TakesSlowPath) == (m_offset == notFound)); + } + + static PutByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&); + + State state() const { return m_state; } + + bool isSet() const { return m_state != NoInformation; } + bool operator!() const { return m_state == NoInformation; } + bool isSimpleReplace() const { return m_state == SimpleReplace; } + bool isSimpleTransition() const { return m_state == SimpleTransition; } + bool takesSlowPath() const { return m_state == TakesSlowPath; } + + Structure* oldStructure() const { return m_oldStructure; } + Structure* newStructure() const { return m_newStructure; } + StructureChain* structureChain() const { return m_structureChain; } + size_t offset() const { return m_offset; } + +private: + State m_state; + Structure* m_oldStructure; + Structure* m_newStructure; + StructureChain* m_structureChain; + size_t m_offset; +}; + +} // namespace JSC + +#endif // PutByIdStatus_h + diff --git a/Source/JavaScriptCore/bytecode/SamplingTool.h b/Source/JavaScriptCore/bytecode/SamplingTool.h index b69ef026e..32a44ad69 100644 --- a/Source/JavaScriptCore/bytecode/SamplingTool.h +++ b/Source/JavaScriptCore/bytecode/SamplingTool.h @@ -45,8 +45,8 @@ namespace JSC { class SamplingFlags { public: - static void start(); - static void stop(); + JS_EXPORT_PRIVATE static void start(); + JS_EXPORT_PRIVATE static void stop(); #if ENABLE(SAMPLING_FLAGS) static void setFlag(unsigned flag) @@ -89,7 +89,7 @@ namespace JSC { #endif private: - static uint32_t s_flags; + JS_EXPORTDATA static uint32_t s_flags; #if ENABLE(SAMPLING_FLAGS) static uint64_t s_flagCounts[33]; #endif @@ -174,7 +174,7 @@ namespace JSC { class SamplingRegion { public: SamplingRegion(const char*) { } - void dump(); + JS_EXPORT_PRIVATE void dump(); }; #endif // ENABLE(SAMPLING_REGIONS) @@ -220,8 +220,8 @@ namespace JSC { static unsigned s_hertz; static ThreadIdentifier s_samplingThread; - static void start(unsigned hertz=10000); - static void stop(); + JS_EXPORT_PRIVATE static void start(unsigned hertz=10000); + JS_EXPORT_PRIVATE static void stop(); static void* threadStartFunc(void*); }; @@ -294,7 +294,7 @@ namespace JSC { memset(m_opcodeSamplesInCTIFunctions, 0, sizeof(m_opcodeSamplesInCTIFunctions)); } - void setup(); + JS_EXPORT_PRIVATE void setup(); void dump(ExecState*); void notifyOfScope(JSGlobalData&, ScriptExecutable* scope); diff --git a/Source/JavaScriptCore/dfg/DFGStructureSet.h b/Source/JavaScriptCore/bytecode/StructureSet.h index 181c32910..344183b45 100644 --- a/Source/JavaScriptCore/dfg/DFGStructureSet.h +++ b/Source/JavaScriptCore/bytecode/StructureSet.h @@ -23,12 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DFGStructureSet_h -#define DFGStructureSet_h - -#include <wtf/Platform.h> - -#if ENABLE(DFG_JIT) +#ifndef StructureSet_h +#define StructureSet_h #include "PredictedType.h" #include <stdio.h> @@ -39,8 +35,8 @@ namespace JSC { class Structure; namespace DFG { - class StructureAbstractValue; +} class StructureSet { public: @@ -140,7 +136,6 @@ public: return true; } -#ifndef NDEBUG void dump(FILE* out) { fprintf(out, "["); @@ -151,16 +146,13 @@ public: } fprintf(out, "]"); } -#endif private: - friend class StructureAbstractValue; + friend class DFG::StructureAbstractValue; Vector<Structure*, 2> m_structures; }; -} } // namespace JSC::DFG - -#endif // ENABLE(DFG_JIT) +} // namespace JSC -#endif // DFGStructureSet_h +#endif // StructureSet_h diff --git a/Source/JavaScriptCore/bytecode/StructureStubInfo.h b/Source/JavaScriptCore/bytecode/StructureStubInfo.h index 5c7ee0bb8..d6b6092d0 100644 --- a/Source/JavaScriptCore/bytecode/StructureStubInfo.h +++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.h @@ -28,6 +28,7 @@ #if ENABLE(JIT) +#include "CodeOrigin.h" #include "Instruction.h" #include "MacroAssembler.h" #include "Opcode.h" @@ -175,6 +176,8 @@ namespace JSC { int8_t seen; #if ENABLE(DFG_JIT) + CodeOrigin codeOrigin; + int8_t registersFlushed; int8_t baseGPR; #if USE(JSVALUE32_64) int8_t valueTagGPR; diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index bfb1618a6..3d363354e 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> + * Copyright (C) 2012 Igalia, S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -117,6 +118,39 @@ namespace JSC { */ #ifndef NDEBUG +void ResolveResult::checkValidity() +{ + switch (m_type) { + case Register: + case ReadOnlyRegister: + ASSERT(m_local); + return; + case Lexical: + case ReadOnlyLexical: + case DynamicLexical: + case DynamicReadOnlyLexical: + ASSERT(m_index != missingSymbolMarker()); + return; + case Global: + case DynamicGlobal: + ASSERT(m_globalObject); + return; + case IndexedGlobal: + case ReadOnlyIndexedGlobal: + case DynamicIndexedGlobal: + case DynamicReadOnlyIndexedGlobal: + ASSERT(m_index != missingSymbolMarker()); + ASSERT(m_globalObject); + return; + case Dynamic: + return; + default: + ASSERT_NOT_REACHED(); + } +} +#endif + +#ifndef NDEBUG static bool s_dumpsGeneratedCode = false; #endif @@ -217,7 +251,7 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* s #ifndef NDEBUG , m_lastOpcodePosition(0) #endif - , m_stack(m_globalData->stack()) + , m_stack(wtfThreadData().stack()) , m_usesExceptions(false) , m_expressionTooDeep(false) { @@ -288,7 +322,7 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainN #ifndef NDEBUG , m_lastOpcodePosition(0) #endif - , m_stack(m_globalData->stack()) + , m_stack(wtfThreadData().stack()) , m_usesExceptions(false) , m_expressionTooDeep(false) { @@ -449,7 +483,7 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, ScopeChainNode* scopeCh #ifndef NDEBUG , m_lastOpcodePosition(0) #endif - , m_stack(m_globalData->stack()) + , m_stack(wtfThreadData().stack()) , m_usesExceptions(false) , m_expressionTooDeep(false) { @@ -503,42 +537,6 @@ void BytecodeGenerator::addParameter(const Identifier& ident, int parameterIndex m_codeBlock->addParameter(); } -RegisterID* BytecodeGenerator::registerFor(const Identifier& ident) -{ - if (ident == propertyNames().thisIdentifier) - return &m_thisRegister; - - if (m_codeType == GlobalCode) - return 0; - - if (!shouldOptimizeLocals()) - return 0; - - SymbolTableEntry entry = symbolTable().get(ident.impl()); - if (entry.isNull()) - return 0; - - if (ident == propertyNames().arguments) - createArgumentsIfNecessary(); - - return createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); -} - -RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident) -{ - if (m_codeType == EvalCode) - return 0; - - if (m_codeType == GlobalCode) - return 0; - - SymbolTableEntry entry = symbolTable().get(ident.impl()); - if (entry.isNull()) - return 0; - - return createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); -} - bool BytecodeGenerator::willResolveToArguments(const Identifier& ident) { if (ident != propertyNames().arguments) @@ -668,6 +666,17 @@ void BytecodeGenerator::emitOpcode(OpcodeID opcodeID) m_lastOpcodeID = opcodeID; } +ValueProfile* BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID) +{ +#if ENABLE(VALUE_PROFILER) + ValueProfile* result = m_codeBlock->addValueProfile(instructions().size()); +#else + ValueProfile* result = 0; +#endif + emitOpcode(opcodeID); + return result; +} + void BytecodeGenerator::emitLoopHint() { #if ENABLE(DFG_JIT) @@ -1159,59 +1168,109 @@ RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v) return constantID; } -bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting, bool& requiresDynamicChecks, JSObject*& globalObject) +ResolveResult BytecodeGenerator::resolve(const Identifier& property) { + if (property == propertyNames().thisIdentifier) + return ResolveResult::registerResolve(thisRegister(), ResolveResult::ReadOnlyFlag); + + // Check if the property should be allocated in a register. + if (m_codeType != GlobalCode && shouldOptimizeLocals()) { + SymbolTableEntry entry = symbolTable().get(property.impl()); + if (!entry.isNull()) { + if (property == propertyNames().arguments) + createArgumentsIfNecessary(); + unsigned flags = entry.isReadOnly() ? ResolveResult::ReadOnlyFlag : 0; + RegisterID* local = createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); + return ResolveResult::registerResolve(local, flags); + } + } + // Cases where we cannot statically optimize the lookup. if (property == propertyNames().arguments || !canOptimizeNonLocals()) { - stackDepth = 0; - index = missingSymbolMarker(); - if (shouldOptimizeLocals() && m_codeType == GlobalCode) { ScopeChainIterator iter = m_scopeChain->begin(); - globalObject = iter->get(); + JSObject* globalObject = iter->get(); ASSERT((++iter) == m_scopeChain->end()); - } - return false; + return ResolveResult::globalResolve(globalObject); + } else + return ResolveResult::dynamicResolve(0); } - size_t depth = 0; - requiresDynamicChecks = false; ScopeChainIterator iter = m_scopeChain->begin(); ScopeChainIterator end = m_scopeChain->end(); + size_t depth = 0; + unsigned flags = 0; for (; iter != end; ++iter, ++depth) { JSObject* currentScope = iter->get(); - if (!currentScope->isVariableObject()) + if (!currentScope->isVariableObject()) { + flags |= ResolveResult::DynamicFlag; break; + } JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope); SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl()); // Found the property if (!entry.isNull()) { - if (entry.isReadOnly() && forWriting) { - stackDepth = 0; - index = missingSymbolMarker(); - if (++iter == end) - globalObject = currentVariableObject; - return false; + if (entry.isReadOnly()) + flags |= ResolveResult::ReadOnlyFlag; + depth += m_codeBlock->needsFullScopeChain(); + if (++iter == end) { + if (flags & ResolveResult::DynamicFlag) + return ResolveResult::dynamicIndexedGlobalResolve(entry.getIndex(), depth, currentScope, flags); + return ResolveResult::indexedGlobalResolve(entry.getIndex(), currentScope, flags); } - stackDepth = depth + m_codeBlock->needsFullScopeChain(); - index = entry.getIndex(); - if (++iter == end) - globalObject = currentVariableObject; - return true; + return ResolveResult::lexicalResolve(entry.getIndex(), depth, flags); } bool scopeRequiresDynamicChecks = false; if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks)) break; - requiresDynamicChecks |= scopeRequiresDynamicChecks; + if (scopeRequiresDynamicChecks) + flags |= ResolveResult::DynamicFlag; } + // Can't locate the property but we're able to avoid a few lookups. - stackDepth = depth + m_codeBlock->needsFullScopeChain(); - index = missingSymbolMarker(); JSObject* scope = iter->get(); - if (++iter == end) - globalObject = scope; - return true; + depth += m_codeBlock->needsFullScopeChain(); + if (++iter == end) { + if ((flags & ResolveResult::DynamicFlag) && depth) + return ResolveResult::dynamicGlobalResolve(depth, scope); + return ResolveResult::globalResolve(scope); + } + return ResolveResult::dynamicResolve(depth); +} + +ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property) +{ + // Register-allocated const declarations. + if (m_codeType != EvalCode && m_codeType != GlobalCode) { + SymbolTableEntry entry = symbolTable().get(property.impl()); + if (!entry.isNull()) { + unsigned flags = entry.isReadOnly() ? ResolveResult::ReadOnlyFlag : 0; + RegisterID* local = createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); + return ResolveResult::registerResolve(local, flags); + } + } + + // Const declarations in eval code or global code. + ScopeChainIterator iter = scopeChain()->begin(); + ScopeChainIterator end = scopeChain()->end(); + size_t depth = 0; + for (; iter != end; ++iter, ++depth) { + JSObject* currentScope = iter->get(); + if (!currentScope->isVariableObject()) + continue; + JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope); + SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl()); + if (entry.isNull()) + continue; + if (++iter == end) + return ResolveResult::indexedGlobalResolve(entry.getIndex(), currentVariableObject, 0); + return ResolveResult::lexicalResolve(entry.getIndex(), depth + scopeDepth(), 0); + } + + // FIXME: While this code should only be hit in an eval block, it will assign + // to the wrong base if property exists in an intervening with scope. + return ResolveResult::dynamicResolve(scopeDepth()); } void BytecodeGenerator::emitCheckHasInstance(RegisterID* base) @@ -1237,246 +1296,222 @@ bool BytecodeGenerator::shouldAvoidResolveGlobal() return m_codeBlock->globalResolveInfoCount() > maxGlobalResolves && !m_labelScopes.size(); } -RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& property) +RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property) { - size_t depth = 0; - int index = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) && !globalObject) { - // We can't optimise at all :-( - emitOpcode(op_resolve); - instructions().append(dst->index()); - instructions().append(addConstant(property)); - return dst; - } - if (shouldAvoidResolveGlobal()) { - globalObject = 0; - requiresDynamicChecks = true; - } - - if (globalObject) { - if (index != missingSymbolMarker() && !requiresDynamicChecks) { - // Directly index the property lookup across multiple scopes. - return emitGetScopedVar(dst, depth, index, globalObject); - } - + if (resolveResult.isStatic()) + return emitGetStaticVar(dst, resolveResult); + + if (resolveResult.isGlobal() && !shouldAvoidResolveGlobal()) { #if ENABLE(JIT) m_codeBlock->addGlobalResolveInfo(instructions().size()); #endif #if ENABLE(INTERPRETER) m_codeBlock->addGlobalResolveInstruction(instructions().size()); #endif - emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); + bool dynamic = resolveResult.isDynamic() && resolveResult.depth(); + ValueProfile* profile = emitProfiledOpcode(dynamic ? op_resolve_global_dynamic : op_resolve_global); instructions().append(dst->index()); instructions().append(addConstant(property)); instructions().append(0); instructions().append(0); - if (requiresDynamicChecks) - instructions().append(depth); + if (dynamic) + instructions().append(resolveResult.depth()); + instructions().append(profile); return dst; } - - if (requiresDynamicChecks) { - // If we get here we have eval nested inside a |with| just give up - emitOpcode(op_resolve); + + if (resolveResult.type() == ResolveResult::Dynamic && resolveResult.depth()) { + // In this case we are at least able to drop a few scope chains from the + // lookup chain, although we still need to hash from then on. + ValueProfile* profile = emitProfiledOpcode(op_resolve_skip); instructions().append(dst->index()); instructions().append(addConstant(property)); + instructions().append(resolveResult.depth()); + instructions().append(profile); return dst; } - if (index != missingSymbolMarker()) { - // Directly index the property lookup across multiple scopes. - return emitGetScopedVar(dst, depth, index, globalObject); - } - - // In this case we are at least able to drop a few scope chains from the - // lookup chain, although we still need to hash from then on. - emitOpcode(op_resolve_skip); + ValueProfile* profile = emitProfiledOpcode(op_resolve); instructions().append(dst->index()); instructions().append(addConstant(property)); - instructions().append(depth); + instructions().append(profile); return dst; } -RegisterID* BytecodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index, JSValue globalObject) +RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property) { - if (globalObject) { - if (m_lastOpcodeID == op_put_global_var) { - int dstIndex; - int srcIndex; - retrieveLastUnaryOp(dstIndex, srcIndex); - - if (dstIndex == index && srcIndex == dst->index()) - return dst; - } + if (resolveResult.isGlobal() && !resolveResult.isDynamic()) + // Global object is the base + return emitLoad(dst, JSValue(resolveResult.globalObject())); - emitOpcode(op_get_global_var); - instructions().append(dst->index()); - instructions().append(index); - return dst; - } - - emitOpcode(op_get_scoped_var); + // We can't optimise at all :-( + ValueProfile* profile = emitProfiledOpcode(op_resolve_base); instructions().append(dst->index()); - instructions().append(index); - instructions().append(depth); + instructions().append(addConstant(property)); + instructions().append(false); + instructions().append(profile); return dst; } -RegisterID* BytecodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value, JSValue globalObject) +RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property) { - if (globalObject) { - emitOpcode(op_put_global_var); - instructions().append(index); - instructions().append(value->index()); - return value; - } - emitOpcode(op_put_scoped_var); - instructions().append(index); - instructions().append(depth); - instructions().append(value->index()); - return value; -} + if (!m_codeBlock->isStrictMode()) + return emitResolveBase(dst, resolveResult, property); -RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property) -{ - size_t depth = 0; - int index = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject); - if (!globalObject || requiresDynamicChecks) { - // We can't optimise at all :-( - emitOpcode(op_resolve_base); + if (resolveResult.isGlobal() && !resolveResult.isDynamic()) { + // Global object is the base + RefPtr<RegisterID> result = emitLoad(dst, JSValue(resolveResult.globalObject())); + emitOpcode(op_ensure_property_exists); instructions().append(dst->index()); instructions().append(addConstant(property)); - instructions().append(false); - return dst; + return result.get(); } - // Global object is the base - return emitLoad(dst, JSValue(globalObject)); -} - -RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Identifier& property) -{ - if (!m_codeBlock->isStrictMode()) - return emitResolveBase(dst, property); - size_t depth = 0; - int index = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject); - if (!globalObject || requiresDynamicChecks) { - // We can't optimise at all :-( - emitOpcode(op_resolve_base); - instructions().append(dst->index()); - instructions().append(addConstant(property)); - instructions().append(true); - return dst; - } - - // Global object is the base - RefPtr<RegisterID> result = emitLoad(dst, JSValue(globalObject)); - emitOpcode(op_ensure_property_exists); + // We can't optimise at all :-( + ValueProfile* profile = emitProfiledOpcode(op_resolve_base); instructions().append(dst->index()); instructions().append(addConstant(property)); - return result.get(); + instructions().append(true); + instructions().append(profile); + return dst; } -RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property) +RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property) { - size_t depth = 0; - int index = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) { - // We can't optimise at all :-( - emitOpcode(op_resolve_with_base); - instructions().append(baseDst->index()); - instructions().append(propDst->index()); - instructions().append(addConstant(property)); - return baseDst; - } + if (resolveResult.isGlobal() && !resolveResult.isDynamic()) { + // Global object is the base + emitLoad(baseDst, JSValue(resolveResult.globalObject())); - bool forceGlobalResolve = false; + if (resolveResult.isStatic()) { + // Directly index the property lookup across multiple scopes. + emitGetStaticVar(propDst, resolveResult); + return baseDst; + } - // Global object is the base - emitLoad(baseDst, JSValue(globalObject)); + if (shouldAvoidResolveGlobal()) { + ValueProfile* profile = emitProfiledOpcode(op_resolve); + instructions().append(propDst->index()); + instructions().append(addConstant(property)); + instructions().append(profile); + return baseDst; + } - if (index != missingSymbolMarker() && !forceGlobalResolve) { - // Directly index the property lookup across multiple scopes. - emitGetScopedVar(propDst, depth, index, globalObject); - return baseDst; - } - if (shouldAvoidResolveGlobal()) { - emitOpcode(op_resolve); - instructions().append(propDst->index()); - instructions().append(addConstant(property)); - return baseDst; - } #if ENABLE(JIT) - m_codeBlock->addGlobalResolveInfo(instructions().size()); + m_codeBlock->addGlobalResolveInfo(instructions().size()); #endif #if ENABLE(INTERPRETER) - m_codeBlock->addGlobalResolveInstruction(instructions().size()); + m_codeBlock->addGlobalResolveInstruction(instructions().size()); #endif - emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); + ValueProfile* profile = emitProfiledOpcode(op_resolve_global); + instructions().append(propDst->index()); + instructions().append(addConstant(property)); + instructions().append(0); + instructions().append(0); + instructions().append(profile); + return baseDst; + } + + + + + ValueProfile* profile = emitProfiledOpcode(op_resolve_with_base); + instructions().append(baseDst->index()); instructions().append(propDst->index()); instructions().append(addConstant(property)); - instructions().append(0); - instructions().append(0); - if (requiresDynamicChecks) - instructions().append(depth); + instructions().append(profile); return baseDst; } -RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const Identifier& property) +RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property) { - size_t depth = 0; - int index = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) { + if (resolveResult.isStatic()) { + emitLoad(baseDst, jsUndefined()); + emitGetStaticVar(propDst, resolveResult); + return baseDst; + } + + if (resolveResult.type() == ResolveResult::Dynamic) { // We can't optimise at all :-( - emitOpcode(op_resolve_with_this); + ValueProfile* profile = emitProfiledOpcode(op_resolve_with_this); instructions().append(baseDst->index()); instructions().append(propDst->index()); instructions().append(addConstant(property)); + instructions().append(profile); return baseDst; } - bool forceGlobalResolve = false; - - // Global object is the base emitLoad(baseDst, jsUndefined()); + return emitResolve(propDst, resolveResult, property); +} - if (index != missingSymbolMarker() && !forceGlobalResolve) { - // Directly index the property lookup across multiple scopes. - emitGetScopedVar(propDst, depth, index, globalObject); - return baseDst; +RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult) +{ + ValueProfile* profile = 0; + + switch (resolveResult.type()) { + case ResolveResult::Register: + case ResolveResult::ReadOnlyRegister: + if (dst == ignoredResult()) + return 0; + return moveToDestinationIfNeeded(dst, resolveResult.local()); + + case ResolveResult::Lexical: + case ResolveResult::ReadOnlyLexical: + profile = emitProfiledOpcode(op_get_scoped_var); + instructions().append(dst->index()); + instructions().append(resolveResult.index()); + instructions().append(resolveResult.depth()); + instructions().append(profile); + return dst; + + case ResolveResult::IndexedGlobal: + case ResolveResult::ReadOnlyIndexedGlobal: + if (m_lastOpcodeID == op_put_global_var) { + int dstIndex; + int srcIndex; + retrieveLastUnaryOp(dstIndex, srcIndex); + if (dstIndex == resolveResult.index() && srcIndex == dst->index()) + return dst; + } + + profile = emitProfiledOpcode(op_get_global_var); + instructions().append(dst->index()); + instructions().append(resolveResult.index()); + instructions().append(profile); + return dst; + + default: + ASSERT_NOT_REACHED(); + return 0; } - if (shouldAvoidResolveGlobal()) { - emitOpcode(op_resolve); - instructions().append(propDst->index()); - instructions().append(addConstant(property)); - return baseDst; +} + +RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, RegisterID* value) +{ + switch (resolveResult.type()) { + case ResolveResult::Register: + case ResolveResult::ReadOnlyRegister: + return moveToDestinationIfNeeded(resolveResult.local(), value); + + case ResolveResult::Lexical: + case ResolveResult::ReadOnlyLexical: + emitOpcode(op_put_scoped_var); + instructions().append(resolveResult.index()); + instructions().append(resolveResult.depth()); + instructions().append(value->index()); + return value; + + case ResolveResult::IndexedGlobal: + case ResolveResult::ReadOnlyIndexedGlobal: + emitOpcode(op_put_global_var); + instructions().append(resolveResult.index()); + instructions().append(value->index()); + return value; + + default: + ASSERT_NOT_REACHED(); + return 0; } -#if ENABLE(JIT) - m_codeBlock->addGlobalResolveInfo(instructions().size()); -#endif -#if ENABLE(INTERPRETER) - m_codeBlock->addGlobalResolveInstruction(instructions().size()); -#endif - emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); - instructions().append(propDst->index()); - instructions().append(addConstant(property)); - instructions().append(0); - instructions().append(0); - if (requiresDynamicChecks) - instructions().append(depth); - return baseDst; } void BytecodeGenerator::emitMethodCheck() @@ -1490,7 +1525,7 @@ RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, co m_codeBlock->addPropertyAccessInstruction(instructions().size()); #endif - emitOpcode(op_get_by_id); + ValueProfile* profile = emitProfiledOpcode(op_get_by_id); instructions().append(dst->index()); instructions().append(base->index()); instructions().append(addConstant(property)); @@ -1498,6 +1533,7 @@ RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, co instructions().append(0); instructions().append(0); instructions().append(0); + instructions().append(profile); return dst; } @@ -1547,22 +1583,13 @@ RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identif return value; } -RegisterID* BytecodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value) +void BytecodeGenerator::emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter) { - emitOpcode(op_put_getter); + emitOpcode(op_put_getter_setter); instructions().append(base->index()); instructions().append(addConstant(property)); - instructions().append(value->index()); - return value; -} - -RegisterID* BytecodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value) -{ - emitOpcode(op_put_setter); - instructions().append(base->index()); - instructions().append(addConstant(property)); - instructions().append(value->index()); - return value; + instructions().append(getter->index()); + instructions().append(setter->index()); } RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property) @@ -1576,11 +1603,12 @@ RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property) { - emitOpcode(op_get_argument_by_val); + ValueProfile* profile = emitProfiledOpcode(op_get_argument_by_val); instructions().append(dst->index()); ASSERT(base->index() == m_codeBlock->argumentsRegister()); instructions().append(base->index()); instructions().append(property->index()); + instructions().append(profile); return dst; } @@ -1599,10 +1627,11 @@ RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, R return dst; } } - emitOpcode(op_get_by_val); + ValueProfile* profile = emitProfiledOpcode(op_get_by_val); instructions().append(dst->index()); instructions().append(base->index()); instructions().append(property->index()); + instructions().append(profile); return dst; } @@ -1824,8 +1853,9 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi instructions().append(0); instructions().append(0); if (dst != ignoredResult()) { - emitOpcode(op_call_put_result); + ValueProfile* profile = emitProfiledOpcode(op_call_put_result); instructions().append(dst->index()); // dst + instructions().append(profile); } if (m_shouldEmitProfileHooks) { @@ -1853,8 +1883,9 @@ RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func instructions().append(arguments->index()); instructions().append(firstFreeRegister->index()); if (dst != ignoredResult()) { - emitOpcode(op_call_put_result); + ValueProfile* profile = emitProfiledOpcode(op_call_put_result); instructions().append(dst->index()); + instructions().append(profile); } if (m_shouldEmitProfileHooks) { emitOpcode(op_profile_did_call); @@ -1926,8 +1957,9 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, instructions().append(0); instructions().append(0); if (dst != ignoredResult()) { - emitOpcode(op_call_put_result); + ValueProfile* profile = emitProfiledOpcode(op_call_put_result); instructions().append(dst->index()); // dst + instructions().append(profile); } if (m_shouldEmitProfileHooks) { @@ -2362,7 +2394,7 @@ void BytecodeGenerator::setIsNumericCompareFunction(bool isNumericCompareFunctio bool BytecodeGenerator::isArgumentNumber(const Identifier& ident, int argumentNumber) { - RegisterID* registerID = registerFor(ident); + RegisterID* registerID = resolve(ident).local(); if (!registerID || registerID->index() >= 0) return 0; return registerID->index() == CallFrame::argumentOffset(argumentNumber); diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h index 3ff5f2343..c9ec5d852 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> + * Copyright (C) 2012 Igalia, S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -85,6 +86,144 @@ namespace JSC { RefPtr<RegisterID> propertyRegister; }; + class ResolveResult { + public: + enum Flags { + // The property is locally bound, in a register. + RegisterFlag = 0x1, + // We need to traverse the scope chain at runtime, checking for + // non-strict eval and/or `with' nodes. + DynamicFlag = 0x2, + // The property was resolved to a definite location, and the + // identifier is not needed any more. + StaticFlag = 0x4, + // Once we have the base object, the property will be located at a + // known index. + IndexedFlag = 0x8, + // Skip some number of objects in the scope chain, given by "depth". + ScopedFlag = 0x10, + // The resolved binding is immutable. + ReadOnlyFlag = 0x20, + // The base object is the global object. + GlobalFlag = 0x40 + }; + enum Type { + // The property is local, and stored in a register. + Register = RegisterFlag | StaticFlag, + // A read-only local, created by "const". + ReadOnlyRegister = RegisterFlag | ReadOnlyFlag | StaticFlag, + // The property is statically scoped free variable. Its coordinates + // are in "index" and "depth". + Lexical = IndexedFlag | ScopedFlag | StaticFlag, + // A read-only Lexical, created by "const". + ReadOnlyLexical = IndexedFlag | ScopedFlag | ReadOnlyFlag | StaticFlag, + // The property was not bound lexically, so at runtime we should + // look directly in the global object. + Global = GlobalFlag, + // Like Global, but we could actually resolve the property to a + // DontDelete property in the global object, for instance, any + // binding created with "var" at the top level. At runtime we'll + // just index into the global object. + IndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag, + // Like IndexedGlobal, but the property is also read-only, like NaN, + // Infinity, or undefined. + ReadOnlyIndexedGlobal = IndexedFlag | ReadOnlyFlag | GlobalFlag | StaticFlag, + // The property could not be resolved statically, due to the + // presence of `with' blocks. At runtime we'll have to walk the + // scope chain. ScopedFlag is set to indicate that "depth" will + // hold some number of nodes to skip in the scope chain, before + // beginning the search. + Dynamic = DynamicFlag | ScopedFlag, + // The property was located as a statically scoped free variable, + // but while traversing the scope chain, there was an intermediate + // activation that used non-strict `eval'. At runtime we'll have to + // check for the absence of this property in those intervening + // scopes. + DynamicLexical = DynamicFlag | IndexedFlag | ScopedFlag, + // Like ReadOnlyLexical, but with intervening non-strict `eval'. + DynamicReadOnlyLexical = DynamicFlag | IndexedFlag | ScopedFlag | ReadOnlyFlag, + // Like Global, but with intervening non-strict `eval'. As with + // Dynamic, ScopeFlag is set to indicate that "depth" does indeed + // store a number of frames to skip before doing the dynamic checks. + DynamicGlobal = DynamicFlag | GlobalFlag | ScopedFlag, + // Like IndexedGlobal, but with intervening non-strict `eval'. + DynamicIndexedGlobal = DynamicFlag | IndexedFlag | GlobalFlag | ScopedFlag, + // Like ReadOnlyIndexedGlobal, but with intervening non-strict + // `eval'. + DynamicReadOnlyIndexedGlobal = DynamicFlag | IndexedFlag | ReadOnlyFlag | GlobalFlag | ScopedFlag, + }; + + static ResolveResult registerResolve(RegisterID *local, unsigned flags) + { + return ResolveResult(Register | flags, local, missingSymbolMarker(), 0, 0); + } + static ResolveResult dynamicResolve(size_t depth) + { + return ResolveResult(Dynamic, 0, missingSymbolMarker(), depth, 0); + } + static ResolveResult lexicalResolve(int index, size_t depth, unsigned flags) + { + unsigned type = (flags & DynamicFlag) ? DynamicLexical : Lexical; + return ResolveResult(type | flags, 0, index, depth, 0); + } + static ResolveResult indexedGlobalResolve(int index, JSObject *globalObject, unsigned flags) + { + return ResolveResult(IndexedGlobal | flags, 0, index, 0, globalObject); + } + static ResolveResult dynamicIndexedGlobalResolve(int index, size_t depth, JSObject *globalObject, unsigned flags) + { + return ResolveResult(DynamicIndexedGlobal | flags, 0, index, depth, globalObject); + } + static ResolveResult globalResolve(JSObject *globalObject) + { + return ResolveResult(Global, 0, missingSymbolMarker(), 0, globalObject); + } + static ResolveResult dynamicGlobalResolve(size_t dynamicDepth, JSObject *globalObject) + { + return ResolveResult(DynamicGlobal, 0, missingSymbolMarker(), dynamicDepth, globalObject); + } + + unsigned type() const { return m_type; } + // Returns the register corresponding to a local variable, or 0 if no + // such register exists. Registers returned by ResolveResult::local() do + // not require explicit reference counting. + RegisterID* local() const { return m_local; } + int index() const { ASSERT (isIndexed() || isRegister()); return m_index; } + size_t depth() const { ASSERT(isScoped()); return m_depth; } + JSObject* globalObject() const { ASSERT(isGlobal()); ASSERT(m_globalObject); return m_globalObject; } + + bool isRegister() const { return m_type & RegisterFlag; } + bool isDynamic() const { return m_type & DynamicFlag; } + bool isStatic() const { return m_type & StaticFlag; } + bool isIndexed() const { return m_type & IndexedFlag; } + bool isScoped() const { return m_type & ScopedFlag; } + bool isReadOnly() const { return (m_type & ReadOnlyFlag) && !isDynamic(); } + bool isGlobal() const { return m_type & GlobalFlag; } + + private: + ResolveResult(unsigned type, RegisterID* local, int index, size_t depth, JSObject* globalObject) + : m_type(type) + , m_index(index) + , m_local(local) + , m_depth(depth) + , m_globalObject(globalObject) + { +#ifndef NDEBUG + checkValidity(); +#endif + } + +#ifndef NDEBUG + void checkValidity(); +#endif + + unsigned m_type; + int m_index; // Index in scope, if IndexedFlag is set + RegisterID* m_local; // Local register, if RegisterFlag is set + size_t m_depth; // Depth in scope chain, if ScopedFlag is set + JSObject* m_globalObject; // If GlobalFlag is set. + }; + class BytecodeGenerator { WTF_MAKE_FAST_ALLOCATED; public: @@ -107,11 +246,6 @@ namespace JSC { JSObject* generate(); - // Returns the register corresponding to a local variable, or 0 if no - // such register exists. Registers returned by registerFor do not - // require explicit reference counting. - RegisterID* registerFor(const Identifier&); - bool isArgumentNumber(const Identifier&, int); void setIsNumericCompareFunction(bool isNumericCompareFunction); @@ -119,17 +253,11 @@ namespace JSC { bool willResolveToArguments(const Identifier&); RegisterID* uncheckedRegisterForArguments(); - // Behaves as registerFor does, but ignores dynamic scope as + // Resolve an identifier, given the current compile-time scope chain. + ResolveResult resolve(const Identifier&); + // Behaves as resolve does, but ignores dynamic scope as // dynamic scope should not interfere with const initialisation - RegisterID* constRegisterFor(const Identifier&); - - // Searches the scope chain in an attempt to statically locate the requested - // property. Returns false if for any reason the property cannot be safely - // optimised at all. Otherwise it will return the index and depth of the - // VariableObject that defines the property. If the property cannot be found - // statically, depth will contain the depth of the scope chain where dynamic - // lookup must begin. - bool findScopedProperty(const Identifier&, int& index, size_t& depth, bool forWriting, bool& includesDynamicScopes, JSObject*& globalObject); + ResolveResult resolveConstDecl(const Identifier&); // Returns the register storing "this" RegisterID* thisRegister() { return &m_thisRegister; } @@ -274,7 +402,7 @@ namespace JSC { return dst; } - return PassRefPtr<RegisterID>(emitNode(n)); + return emitNode(n); } RegisterID* emitLoad(RegisterID* dst, bool); @@ -309,14 +437,14 @@ namespace JSC { 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()); } - RegisterID* emitResolve(RegisterID* dst, const Identifier& property); - RegisterID* emitGetScopedVar(RegisterID* dst, size_t skip, int index, JSValue globalObject); - RegisterID* emitPutScopedVar(size_t skip, int index, RegisterID* value, JSValue globalObject); + RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&); + RegisterID* emitPutStaticVar(const ResolveResult&, RegisterID* value); - RegisterID* emitResolveBase(RegisterID* dst, const Identifier& property); - RegisterID* emitResolveBaseForPut(RegisterID* dst, const Identifier& property); - RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property); - RegisterID* emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const Identifier& property); + RegisterID* emitResolve(RegisterID* dst, const ResolveResult&, const Identifier& property); + RegisterID* emitResolveBase(RegisterID* dst, const ResolveResult&, const Identifier& property); + RegisterID* emitResolveBaseForPut(RegisterID* dst, const ResolveResult&, const Identifier& property); + RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property); + RegisterID* emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property); void emitMethodCheck(); @@ -330,8 +458,7 @@ namespace JSC { RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property); RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value); - RegisterID* emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value); - RegisterID* emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value); + void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter); RegisterID* emitCall(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); @@ -409,6 +536,7 @@ namespace JSC { private: void emitOpcode(OpcodeID); + ValueProfile* emitProfiledOpcode(OpcodeID); void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); ALWAYS_INLINE void rewindBinaryOp(); @@ -466,12 +594,12 @@ namespace JSC { FunctionExecutable* makeFunction(ExecState* exec, FunctionBodyNode* body) { - return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); + return FunctionExecutable::create(exec, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); } FunctionExecutable* makeFunction(JSGlobalData* globalData, FunctionBodyNode* body) { - return FunctionExecutable::create(*globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); + return FunctionExecutable::create(*globalData, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); } JSString* addStringConstant(const Identifier&); diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp index a0127d8d7..46ec698de 100644 --- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -5,6 +5,7 @@ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) * Copyright (C) 2007 Maks Orlovich * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2012 Igalia, S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -146,14 +147,15 @@ bool ResolveNode::isPure(BytecodeGenerator& generator) const RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (RegisterID* local = generator.registerFor(m_ident)) { + ResolveResult resolveResult = generator.resolve(m_ident); + if (RegisterID* local = resolveResult.local()) { if (dst == generator.ignoredResult()) return 0; return generator.moveToDestinationIfNeeded(dst, local); } generator.emitExpressionInfo(m_startOffset + m_ident.length(), m_ident.length(), 0); - return generator.emitResolve(generator.finalDestination(dst), m_ident); + return generator.emitResolve(generator.finalDestination(dst), resolveResult, m_ident); } // ------------------------------ ArrayNode ------------------------------------ @@ -236,27 +238,79 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe generator.emitNewObject(newObj.get()); - for (PropertyListNode* p = this; p; p = p->m_next) { - RegisterID* value = generator.emitNode(p->m_node->m_assign); - - switch (p->m_node->m_type) { - case PropertyNode::Constant: { - generator.emitDirectPutById(newObj.get(), p->m_node->name(), value); - break; - } - case PropertyNode::Getter: { - generator.emitPutGetter(newObj.get(), p->m_node->name(), value); - break; + // Fast case: this loop just handles regular value properties. + PropertyListNode* p = this; + for (; p && p->m_node->m_type == PropertyNode::Constant; p = p->m_next) + generator.emitDirectPutById(newObj.get(), p->m_node->name(), generator.emitNode(p->m_node->m_assign)); + + // Were there any get/set properties? + if (p) { + typedef std::pair<PropertyNode*, PropertyNode*> GetterSetterPair; + typedef HashMap<StringImpl*, GetterSetterPair> GetterSetterMap; + GetterSetterMap map; + + // Build a map, pairing get/set values together. + for (PropertyListNode* q = p; q; q = q->m_next) { + PropertyNode* node = q->m_node; + if (node->m_type == PropertyNode::Constant) + continue; + + GetterSetterPair pair(node, 0); + std::pair<GetterSetterMap::iterator, bool> result = map.add(node->name().impl(), pair); + if (!result.second) + result.first->second.second = node; + } + + // Iterate over the remaining properties in the list. + for (; p; p = p->m_next) { + PropertyNode* node = p->m_node; + RegisterID* value = generator.emitNode(node->m_assign); + + // Handle regular values. + if (node->m_type == PropertyNode::Constant) { + generator.emitDirectPutById(newObj.get(), node->name(), value); + continue; } - case PropertyNode::Setter: { - generator.emitPutSetter(newObj.get(), p->m_node->name(), value); - break; + + // This is a get/set property, find its entry in the map. + ASSERT(node->m_type == PropertyNode::Getter || node->m_type == PropertyNode::Setter); + GetterSetterMap::iterator it = map.find(node->name().impl()); + ASSERT(it != map.end()); + GetterSetterPair& pair = it->second; + + // Was this already generated as a part of its partner? + if (pair.second == node) + continue; + + // Generate the paired node now. + RefPtr<RegisterID> getterReg; + RefPtr<RegisterID> setterReg; + + if (node->m_type == PropertyNode::Getter) { + getterReg = value; + if (pair.second) { + ASSERT(pair.second->m_type == PropertyNode::Setter); + setterReg = generator.emitNode(pair.second->m_assign); + } else { + setterReg = generator.newTemporary(); + generator.emitLoad(setterReg.get(), jsUndefined()); + } + } else { + ASSERT(node->m_type == PropertyNode::Setter); + setterReg = value; + if (pair.second) { + ASSERT(pair.second->m_type == PropertyNode::Getter); + getterReg = generator.emitNode(pair.second->m_assign); + } else { + getterReg = generator.newTemporary(); + generator.emitLoad(getterReg.get(), jsUndefined()); + } } - default: - ASSERT_NOT_REACHED(); + + generator.emitPutGetterSetter(newObj.get(), node->name(), getterReg.get(), setterReg.get()); } } - + return generator.moveToDestinationIfNeeded(dst, newObj.get()); } @@ -346,7 +400,7 @@ RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, Reg RefPtr<RegisterID> func = generator.tempDestination(dst); CallArguments callArguments(generator, m_args); generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); - generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), generator.propertyNames().eval); + generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), generator.resolve(generator.propertyNames().eval), generator.propertyNames().eval); return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); } @@ -364,19 +418,19 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) { + ResolveResult resolveResult = generator.resolve(m_ident); + + if (RegisterID* local = resolveResult.local()) { + RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local); CallArguments callArguments(generator, m_args); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), local.get(), callArguments, divot(), startOffset(), endOffset()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), callArguments, divot(), startOffset(), endOffset()); } - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (generator.findScopedProperty(m_ident, index, depth, false, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { - RefPtr<RegisterID> func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); + if (resolveResult.isStatic()) { + RefPtr<RegisterID> func = generator.newTemporary(); CallArguments callArguments(generator, m_args); + generator.emitGetStaticVar(func.get(), resolveResult); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); } @@ -384,8 +438,9 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RefPtr<RegisterID> func = generator.newTemporary(); CallArguments callArguments(generator, m_args); int identifierStart = divot() - startOffset(); + generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0); - generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), m_ident); + generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), resolveResult, m_ident); return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); } @@ -505,6 +560,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RefPtr<RegisterID> profileHookRegister; if (generator.shouldEmitProfileHooks()) profileHookRegister = generator.newTemporary(); + RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); RefPtr<RegisterID> thisRegister = generator.emitNode(m_args->m_listNode->m_expr); RefPtr<RegisterID> argsRegister; ArgumentListNode* args = m_args->m_listNode->m_next; @@ -518,7 +574,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, while ((args = args->m_next)) generator.emitNode(args->m_expr); - generator.emitCallVarargs(finalDestinationOrIgnored.get(), base.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), profileHookRegister.get(), divot(), startOffset(), endOffset()); + generator.emitCallVarargs(finalDestinationOrIgnored.get(), realFunction.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), profileHookRegister.get(), divot(), startOffset(), endOffset()); } generator.emitJump(end.get()); } @@ -548,24 +604,21 @@ static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* ds RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { + ResolveResult resolveResult = generator.resolve(m_ident); + + if (RegisterID* local = resolveResult.local()) { + if (resolveResult.isReadOnly()) { if (dst == generator.ignoredResult()) return 0; return generator.emitToJSNumber(generator.finalDestination(dst), local); } - if (dst == generator.ignoredResult()) return emitPreIncOrDec(generator, local, m_operator); return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator); } - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { - RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); + if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { + RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult); RegisterID* oldValue; if (dst == generator.ignoredResult()) { oldValue = 0; @@ -573,13 +626,13 @@ RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, Regis } else { oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); } - generator.emitPutScopedVar(depth, index, value.get(), globalObject); + generator.emitPutStaticVar(resolveResult, value.get()); return oldValue; } - + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); RefPtr<RegisterID> value = generator.newTemporary(); - RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident); + RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), resolveResult, m_ident); RegisterID* oldValue; if (dst == generator.ignoredResult()) { oldValue = 0; @@ -651,11 +704,12 @@ RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, Registe RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (generator.registerFor(m_ident)) + ResolveResult resolveResult = generator.resolve(m_ident); + if (resolveResult.isRegister()) return generator.emitLoad(generator.finalDestination(dst), false); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident); + RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), resolveResult, m_ident); return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident); } @@ -706,13 +760,14 @@ RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (RegisterID* local = generator.registerFor(m_ident)) { + ResolveResult resolveResult = generator.resolve(m_ident); + if (RegisterID* local = resolveResult.local()) { if (dst == generator.ignoredResult()) return 0; return generator.emitTypeOf(generator.finalDestination(dst), local); } - RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident); + RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), resolveResult, m_ident); generator.emitGetById(scratch.get(), scratch.get(), m_ident); if (dst == generator.ignoredResult()) return 0; @@ -735,32 +790,28 @@ RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, Register RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (RegisterID* local = generator.registerFor(m_ident)) { + ResolveResult resolveResult = generator.resolve(m_ident); + if (RegisterID* local = resolveResult.local()) { if (generator.isLocalConstant(m_ident)) { if (dst == generator.ignoredResult()) return 0; RefPtr<RegisterID> r0 = generator.emitLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0); return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes()); } - emitPreIncOrDec(generator, local, m_operator); return generator.moveToDestinationIfNeeded(dst, local); } - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { - RefPtr<RegisterID> propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); + if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { + RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult); emitPreIncOrDec(generator, propDst.get(), m_operator); - generator.emitPutScopedVar(depth, index, propDst.get(), globalObject); + generator.emitPutStaticVar(resolveResult, propDst.get()); return generator.moveToDestinationIfNeeded(dst, propDst.get()); } generator.emitExpressionInfo(divot(), startOffset(), endOffset()); RefPtr<RegisterID> propDst = generator.tempDestination(dst); - RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident); + RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), resolveResult, m_ident); emitPreIncOrDec(generator, propDst.get(), m_operator); generator.emitPutById(base.get(), m_ident, propDst.get()); return generator.moveToDestinationIfNeeded(dst, propDst.get()); @@ -1148,10 +1199,11 @@ static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& gen RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { + ResolveResult resolveResult = generator.resolve(m_ident); + + if (RegisterID *local = resolveResult.local()) { + if (resolveResult.isReadOnly()) return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - } if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { RefPtr<RegisterID> result = generator.newTemporary(); @@ -1165,20 +1217,16 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re return generator.moveToDestinationIfNeeded(dst, result); } - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { - RefPtr<RegisterID> src1 = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); + if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { + RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult); RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - generator.emitPutScopedVar(depth, index, result, globalObject); + generator.emitPutStaticVar(resolveResult, result); return result; } RefPtr<RegisterID> src1 = generator.tempDestination(dst); generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0); - RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident); + RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), resolveResult, m_ident); RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); return generator.emitPutById(base.get(), m_ident, result); } @@ -1187,27 +1235,24 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) + ResolveResult resolveResult = generator.resolve(m_ident); + + if (RegisterID *local = resolveResult.local()) { + if (resolveResult.isReadOnly()) return generator.emitNode(dst, m_right); - RegisterID* result = generator.emitNode(local, m_right); return generator.moveToDestinationIfNeeded(dst, result); } - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { + if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { if (dst == generator.ignoredResult()) dst = 0; RegisterID* value = generator.emitNode(dst, m_right); - generator.emitPutScopedVar(depth, index, value, globalObject); + generator.emitPutStaticVar(resolveResult, value); return value; } - RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), m_ident); + RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident); if (dst == generator.ignoredResult()) dst = 0; RegisterID* value = generator.emitNode(dst, m_right); @@ -1295,8 +1340,10 @@ RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) { + ResolveResult resolveResult = generator.resolveConstDecl(m_ident); + // FIXME: This code does not match the behavior of const in Firefox. - if (RegisterID* local = generator.constRegisterFor(m_ident)) { + if (RegisterID* local = resolveResult.local()) { if (!m_init) return local; @@ -1305,27 +1352,15 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); - ScopeChainIterator iter = generator.scopeChain()->begin(); - ScopeChainIterator end = generator.scopeChain()->end(); - size_t depth = 0; - for (; iter != end; ++iter, ++depth) { - JSObject* currentScope = iter->get(); - if (!currentScope->isVariableObject()) - continue; - JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope); - SymbolTableEntry entry = currentVariableObject->symbolTable().get(m_ident.impl()); - if (entry.isNull()) - continue; - - return generator.emitPutScopedVar(generator.scopeDepth() + depth, entry.getIndex(), value.get(), currentVariableObject->isGlobalObject() ? currentVariableObject : 0); - } - + if (resolveResult.isStatic()) + return generator.emitPutStaticVar(resolveResult, value.get()); + if (generator.codeType() != EvalCode) return value.get(); // FIXME: While this code should only be hit in an eval block, it will assign // to the wrong base if m_ident exists in an intervening with scope. - RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); + RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), resolveResult, m_ident); return generator.emitPutById(base.get(), m_ident, value.get()); } @@ -1596,11 +1631,12 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds bool optimizedForinAccess = false; if (m_lexpr->isResolveNode()) { const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); - propertyName = generator.registerFor(ident); + ResolveResult resolveResult = generator.resolve(ident); + propertyName = resolveResult.local(); if (!propertyName) { propertyName = generator.newTemporary(); RefPtr<RegisterID> protect = propertyName; - RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), ident); + RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); generator.emitPutById(base, ident, propertyName); @@ -1933,13 +1969,7 @@ RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) // Uncaught exception path: the catch block. RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); RefPtr<RegisterID> exceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get()); - if (m_catchHasEval) { - RefPtr<RegisterID> dynamicScopeObject = generator.emitNewObject(generator.newTemporary()); - generator.emitPutById(dynamicScopeObject.get(), m_exceptionIdent, exceptionRegister.get()); - generator.emitMove(exceptionRegister.get(), dynamicScopeObject.get()); - generator.emitPushScope(exceptionRegister.get()); - } else - generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get()); + generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get()); generator.emitNode(dst, m_catchBlock); generator.emitPopScope(); generator.emitLabel(catchEndLabel.get()); diff --git a/Source/JavaScriptCore/config.h b/Source/JavaScriptCore/config.h index d778f63a8..ba65476a5 100644 --- a/Source/JavaScriptCore/config.h +++ b/Source/JavaScriptCore/config.h @@ -32,6 +32,9 @@ // WTF cannot depend on JSC even if USE(JSC). #if USE(JSC) && !defined(BUILDING_WTF) #include "JSExportMacros.h" +#elif PLATFORM(CHROMIUM) +// Chromium doesn't have runtime/ in its include paths. +#include "runtime/JSExportMacros.h" #endif #if OS(WINDOWS) diff --git a/Source/JavaScriptCore/debugger/Debugger.h b/Source/JavaScriptCore/debugger/Debugger.h index f48243c45..a23732918 100644 --- a/Source/JavaScriptCore/debugger/Debugger.h +++ b/Source/JavaScriptCore/debugger/Debugger.h @@ -58,7 +58,7 @@ namespace JSC { }; // This function exists only for backwards compatibility with existing WebScriptDebugger clients. - JSValue evaluateInGlobalCallFrame(const UString&, JSValue& exception, JSGlobalObject*); + JS_EXPORT_PRIVATE JSValue evaluateInGlobalCallFrame(const UString&, JSValue& exception, JSGlobalObject*); } // namespace JSC diff --git a/Source/JavaScriptCore/debugger/DebuggerActivation.cpp b/Source/JavaScriptCore/debugger/DebuggerActivation.cpp index 80be310b5..330476da2 100644 --- a/Source/JavaScriptCore/debugger/DebuggerActivation.cpp +++ b/Source/JavaScriptCore/debugger/DebuggerActivation.cpp @@ -77,10 +77,10 @@ void DebuggerActivation::put(JSCell* cell, ExecState* exec, const Identifier& pr thisObject->m_activation->methodTable()->put(thisObject->m_activation.get(), exec, propertyName, value, slot); } -void DebuggerActivation::putWithAttributes(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) +void DebuggerActivation::putDirectVirtual(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) { DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(object); - thisObject->m_activation->methodTable()->putWithAttributes(thisObject->m_activation.get(), exec, propertyName, value, attributes); + thisObject->m_activation->methodTable()->putDirectVirtual(thisObject->m_activation.get(), exec, propertyName, value, attributes); } bool DebuggerActivation::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName) diff --git a/Source/JavaScriptCore/debugger/DebuggerActivation.h b/Source/JavaScriptCore/debugger/DebuggerActivation.h index c28d0b3a2..8dba70b80 100644 --- a/Source/JavaScriptCore/debugger/DebuggerActivation.h +++ b/Source/JavaScriptCore/debugger/DebuggerActivation.h @@ -45,14 +45,14 @@ namespace JSC { static UString className(const JSObject*); static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&); static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); - static void putWithAttributes(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); + static void putDirectVirtual(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName); static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); static void defineGetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes); static void defineSetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes); - static const ClassInfo s_info; + JS_EXPORTDATA static const ClassInfo s_info; static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) { @@ -62,10 +62,10 @@ namespace JSC { protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | JSObject::StructureFlags; - void finishCreation(JSGlobalData&, JSObject* activation); + JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&, JSObject* activation); private: - DebuggerActivation(JSGlobalData&); + JS_EXPORT_PRIVATE DebuggerActivation(JSGlobalData&); WriteBarrier<JSActivation> m_activation; }; diff --git a/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp b/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp index 08fba4a6b..6a8cdb2dc 100644 --- a/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp +++ b/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp @@ -56,10 +56,11 @@ UString DebuggerCallFrame::calculatedFunctionName() const return UString(); JSObject* function = m_callFrame->callee(); - if (!function || !function->inherits(&JSFunction::s_info)) + + if (!function) return UString(); - return asFunction(function)->calculatedDisplayName(m_callFrame); + return getCalculatedDisplayName(m_callFrame, function); } DebuggerCallFrame::Type DebuggerCallFrame::type() const diff --git a/Source/JavaScriptCore/debugger/DebuggerCallFrame.h b/Source/JavaScriptCore/debugger/DebuggerCallFrame.h index d8fb9dae5..8605af54d 100644 --- a/Source/JavaScriptCore/debugger/DebuggerCallFrame.h +++ b/Source/JavaScriptCore/debugger/DebuggerCallFrame.h @@ -50,7 +50,7 @@ namespace JSC { JSGlobalObject* dynamicGlobalObject() const { return m_callFrame->dynamicGlobalObject(); } ScopeChainNode* scopeChain() const { return m_callFrame->scopeChain(); } - const UString* functionName() const; + JS_EXPORT_PRIVATE const UString* functionName() const; JS_EXPORT_PRIVATE UString calculatedFunctionName() const; JS_EXPORT_PRIVATE Type type() const; JS_EXPORT_PRIVATE JSObject* thisObject() const; diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index eb00bcb3c..bd35e1d43 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -121,6 +121,8 @@ void AbstractState::initialize(Graph& graph) root->valuesAtHead.argument(i).set(PredictInt32Array); else if (isUint8ArrayPrediction(prediction)) root->valuesAtHead.argument(i).set(PredictUint8Array); + else if (isUint8ClampedArrayPrediction(prediction)) + root->valuesAtHead.argument(i).set(PredictUint8ClampedArray); else if (isUint16ArrayPrediction(prediction)) root->valuesAtHead.argument(i).set(PredictUint16Array); else if (isUint32ArrayPrediction(prediction)) @@ -151,14 +153,14 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode) if (mergeMode != DontMerge || !ASSERT_DISABLED) { for (size_t argument = 0; argument < block->variablesAtTail.numberOfArguments(); ++argument) { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - printf(" Merging state for argument %lu.\n", argument); + printf(" Merging state for argument %zu.\n", argument); #endif changed |= mergeStateAtTail(block->valuesAtTail.argument(argument), m_variables.argument(argument), block->variablesAtTail.argument(argument)); } for (size_t local = 0; local < block->variablesAtTail.numberOfLocals(); ++local) { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - printf(" Merging state for local %lu.\n", local); + printf(" Merging state for local %zu.\n", local); #endif changed |= mergeStateAtTail(block->valuesAtTail.local(local), m_variables.local(local), block->variablesAtTail.local(local)); } @@ -278,7 +280,7 @@ bool AbstractState::execute(NodeIndex nodeIndex) case ValueAdd: case ArithAdd: { - if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) { + if (m_graph.addShouldSpeculateInteger(node, m_codeBlock)) { forNode(node.child1()).filter(PredictInt32); forNode(node.child2()).filter(PredictInt32); forNode(nodeIndex).set(PredictInt32); @@ -296,7 +298,19 @@ bool AbstractState::execute(NodeIndex nodeIndex) break; } - case ArithSub: + case ArithSub: { + if (m_graph.addShouldSpeculateInteger(node, m_codeBlock)) { + forNode(node.child1()).filter(PredictInt32); + forNode(node.child2()).filter(PredictInt32); + forNode(nodeIndex).set(PredictInt32); + break; + } + forNode(node.child1()).filter(PredictNumber); + forNode(node.child2()).filter(PredictNumber); + forNode(nodeIndex).set(PredictDouble); + break; + } + case ArithMul: case ArithDiv: case ArithMin: @@ -448,6 +462,12 @@ bool AbstractState::execute(NodeIndex nodeIndex) forNode(nodeIndex).set(PredictInt32); break; } + if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { + forNode(node.child1()).filter(PredictUint8ClampedArray); + forNode(node.child2()).filter(PredictInt32); + forNode(nodeIndex).set(PredictInt32); + break; + } if (m_graph[node.child1()].shouldSpeculateUint16Array()) { forNode(node.child1()).filter(PredictUint16Array); forNode(node.child2()).filter(PredictInt32); @@ -522,6 +542,12 @@ bool AbstractState::execute(NodeIndex nodeIndex) forNode(node.child3()).filter(PredictNumber); break; } + if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { + forNode(node.child1()).filter(PredictUint8ClampedArray); + forNode(node.child2()).filter(PredictInt32); + forNode(node.child3()).filter(PredictNumber); + break; + } if (m_graph[node.child1()].shouldSpeculateUint16Array()) { forNode(node.child1()).filter(PredictUint16Array); forNode(node.child2()).filter(PredictInt32); @@ -688,6 +714,7 @@ bool AbstractState::execute(NodeIndex nodeIndex) break; case GetById: + case GetByIdFlush: if (!node.prediction()) { m_isValid = false; break; @@ -728,6 +755,10 @@ bool AbstractState::execute(NodeIndex nodeIndex) forNode(node.child1()).filter(PredictUint8Array); forNode(nodeIndex).set(PredictInt32); break; + case GetUint8ClampedArrayLength: + forNode(node.child1()).filter(PredictUint8ClampedArray); + forNode(nodeIndex).set(PredictInt32); + break; case GetUint16ArrayLength: forNode(node.child1()).filter(PredictUint16Array); forNode(nodeIndex).set(PredictInt32); @@ -797,6 +828,11 @@ bool AbstractState::execute(NodeIndex nodeIndex) forNode(nodeIndex).clear(); break; } + if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { + forNode(node.child1()).filter(PredictUint8ClampedArray); + forNode(nodeIndex).clear(); + break; + } if (m_graph[node.child1()].shouldSpeculateUint16Array()) { forNode(node.child1()).filter(PredictUint16Array); forNode(nodeIndex).set(PredictOther); diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h index ee43b6c4a..15bc0d496 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h +++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h @@ -30,9 +30,9 @@ #if ENABLE(DFG_JIT) -#include "DFGStructureSet.h" #include "JSCell.h" #include "PredictedType.h" +#include "StructureSet.h" namespace JSC { namespace DFG { diff --git a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h index a9dec5062..e0d817c9f 100644 --- a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h @@ -246,6 +246,16 @@ public: m_assembler.vmov(fpr, payloadGPR, tagGPR); } #endif + + enum ExceptionCheckKind { NormalExceptionCheck, InvertedExceptionCheck }; + Jump emitExceptionCheck(ExceptionCheckKind kind = NormalExceptionCheck) + { +#if USE(JSVALUE64) + return branchTestPtr(kind == NormalExceptionCheck ? NonZero : Zero, AbsoluteAddress(&globalData()->exception)); +#elif USE(JSVALUE32_64) + return branch32(kind == NormalExceptionCheck ? NotEqual : Equal, AbsoluteAddress(reinterpret_cast<char*>(&globalData()->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); +#endif + } #if ENABLE(SAMPLING_COUNTERS) static void emitCount(MacroAssembler& jit, AbstractSamplingCounter& counter, int32_t increment = 1) diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 964618c43..87c3a23b9 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -28,9 +28,13 @@ #if ENABLE(DFG_JIT) +#include "CallLinkStatus.h" +#include "CodeBlock.h" #include "DFGByteCodeCache.h" #include "DFGCapabilities.h" -#include "CodeBlock.h" +#include "GetByIdStatus.h" +#include "MethodCallLinkStatus.h" +#include "PutByIdStatus.h" #include <wtf/HashMap.h> #include <wtf/MathExtras.h> @@ -48,6 +52,7 @@ public: , m_graph(graph) , m_currentBlock(0) , m_currentIndex(0) + , m_currentProfilingIndex(0) , m_constantUndefined(UINT_MAX) , m_constantNull(UINT_MAX) , m_constantNaN(UINT_MAX) @@ -329,7 +334,8 @@ private: JSValue v = valueOfJSConstant(index); if (v.isInt32()) return getJSConstant(node.constantNumber()); - // FIXME: We could convert the double ToInteger at this point. + if (v.isNumber()) + return getJSConstantForValue(JSValue(JSC::toInt32(v.asNumber()))); } return addToGraph(ValueToInt32, index); @@ -351,6 +357,17 @@ private: return addToGraph(ValueToNumber, OpInfo(NodeUseBottom), index); } + + NodeIndex getJSConstantForValue(JSValue constantValue) + { + unsigned constantIndex = m_codeBlock->addOrFindConstant(constantValue); + if (constantIndex >= m_constants.size()) + m_constants.append(ConstantRecord()); + + ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); + + return getJSConstant(constantIndex); + } NodeIndex getJSConstant(unsigned constant) { @@ -382,16 +399,6 @@ private: { return isJSConstant(nodeIndex) && valueOfJSConstant(nodeIndex).isInt32(); } - bool isSmallInt32Constant(NodeIndex nodeIndex) - { - if (!isJSConstant(nodeIndex)) - return false; - JSValue value = valueOfJSConstant(nodeIndex); - if (!value.isInt32()) - return false; - int32_t intValue = value.asInt32(); - return intValue >= -5 && intValue <= 5; - } // Convenience methods for getting constant values. JSValue valueOfJSConstant(NodeIndex index) { @@ -403,7 +410,7 @@ private: ASSERT(isInt32Constant(nodeIndex)); return valueOfJSConstant(nodeIndex).asInt32(); } - + // This method returns a JSConstant with the value 'undefined'. NodeIndex constantUndefined() { @@ -519,7 +526,7 @@ private: CodeOrigin currentCodeOrigin() { - return CodeOrigin(m_currentIndex, m_inlineStackTop->m_inlineCallFrame); + return CodeOrigin(m_currentIndex, m_inlineStackTop->m_inlineCallFrame, m_currentProfilingIndex - m_currentIndex); } // These methods create a node and add it to the graph. If nodes of this type are @@ -574,8 +581,10 @@ private: Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call); PredictedType prediction = PredictNone; - if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) - prediction = getPrediction(m_graph.size(), m_currentIndex + OPCODE_LENGTH(op_call)); + if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { + m_currentProfilingIndex = m_currentIndex + OPCODE_LENGTH(op_call); + prediction = getPrediction(); + } addVarArgChild(get(currentInstruction[1].u.operand)); int argCount = currentInstruction[2].u.operand; @@ -622,12 +631,12 @@ private: PredictedType getPredictionWithoutOSRExit() { - return getPredictionWithoutOSRExit(m_graph.size(), m_currentIndex); + return getPredictionWithoutOSRExit(m_graph.size(), m_currentProfilingIndex); } PredictedType getPrediction() { - return getPrediction(m_graph.size(), m_currentIndex); + return getPrediction(m_graph.size(), m_currentProfilingIndex); } NodeIndex makeSafe(NodeIndex nodeIndex) @@ -700,6 +709,29 @@ private: return nodeIndex; } + bool willNeedFlush(StructureStubInfo& stubInfo) + { + PolymorphicAccessStructureList* list; + int listSize; + switch (stubInfo.accessType) { + case access_get_by_id_self_list: + list = stubInfo.u.getByIdSelfList.structureList; + listSize = stubInfo.u.getByIdSelfList.listSize; + break; + case access_get_by_id_proto_list: + list = stubInfo.u.getByIdProtoList.structureList; + listSize = stubInfo.u.getByIdProtoList.listSize; + break; + default: + return false; + } + for (int i = 0; i < listSize; ++i) { + if (!list->list[i].isDirect) + return true; + } + return false; + } + bool structureChainIsStillValid(bool direct, Structure* previousStructure, StructureChain* chain) { if (direct) @@ -727,6 +759,8 @@ private: BasicBlock* m_currentBlock; // The bytecode index of the current instruction being generated. unsigned m_currentIndex; + // The bytecode index of the value profile of the current instruction being generated. + unsigned m_currentProfilingIndex; // We use these values during code generation, and to avoid the need for // special handling we make sure they are available as constants in the @@ -890,6 +924,7 @@ private: m_currentIndex += OPCODE_LENGTH(name); \ return shouldContinueParsing + void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentInstruction, NodeType op, CodeSpecializationKind kind) { ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); @@ -898,13 +933,15 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn enum { ConstantFunction, LinkedFunction, UnknownFunction } callType; #if DFG_ENABLE(DEBUG_VERBOSE) - printf("Slow case count for call at @%lu bc#%u: %u/%u; exit profile: %d.\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_profiledBlock->executionEntryCount(), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); + printf("Slow case count for call at @%zu bc#%u: %u/%u; exit profile: %d.\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_profiledBlock->executionEntryCount(), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); #endif - + + CallLinkStatus callLinkStatus = CallLinkStatus::computeFor( + m_inlineStackTop->m_profiledBlock, m_currentIndex); + if (m_graph.isFunctionConstant(m_codeBlock, callTarget)) callType = ConstantFunction; - else if (!!m_inlineStackTop->m_profiledBlock->getCallLinkInfo(m_currentIndex).lastSeenCallee - && !m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) + else if (callLinkStatus.isSet() && !callLinkStatus.couldTakeSlowPath() && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) callType = LinkedFunction; else @@ -922,7 +959,8 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { resultOperand = putInstruction[1].u.operand; usesResult = true; - prediction = getPrediction(m_graph.size(), nextOffset); + m_currentProfilingIndex = nextOffset; + prediction = getPrediction(); nextOffset += OPCODE_LENGTH(op_call_put_result); } JSFunction* expectedFunction; @@ -934,7 +972,7 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn certainAboutExpectedFunction = true; } else { ASSERT(callType == LinkedFunction); - expectedFunction = m_inlineStackTop->m_profiledBlock->getCallLinkInfo(m_currentIndex).lastSeenCallee.get(); + expectedFunction = callLinkStatus.callTarget(); intrinsic = expectedFunction->executable()->intrinsicFor(kind); certainAboutExpectedFunction = false; } @@ -1029,7 +1067,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c int inlineCallFrameStart = m_inlineStackTop->remapOperand(registerOffset) - RegisterFile::CallFrameHeaderSize; // Make sure that the area used by the call frame is reserved. - for (int arg = inlineCallFrameStart + RegisterFile::CallFrameHeaderSize + codeBlock->m_numVars; arg-- > inlineCallFrameStart + 1;) + for (int arg = inlineCallFrameStart + RegisterFile::CallFrameHeaderSize + codeBlock->m_numVars; arg-- > inlineCallFrameStart;) m_preservedVars.set(m_inlineStackTop->remapOperand(arg)); // Make sure that we have enough locals. @@ -1044,13 +1082,16 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c // This is where the actual inlining really happens. unsigned oldIndex = m_currentIndex; + unsigned oldProfilingIndex = m_currentProfilingIndex; m_currentIndex = 0; + m_currentProfilingIndex = 0; addToGraph(InlineStart); parseCodeBlock(); m_currentIndex = oldIndex; + m_currentProfilingIndex = oldProfilingIndex; // If the inlined code created some new basic blocks, then we have linking to do. if (inlineStackEntry.m_callsiteBlockHead != m_graph.m_blocks.size() - 1) { @@ -1129,7 +1170,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c // Need to create a new basic block for the continuation at the caller. OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(nextOffset, m_graph.size(), m_numArguments, m_numLocals)); #if DFG_ENABLE(DEBUG_VERBOSE) - printf("Creating inline epilogue basic block %p, #%lu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame)); + printf("Creating inline epilogue basic block %p, #%zu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame)); #endif m_currentBlock = block.get(); ASSERT(m_inlineStackTop->m_caller->m_blockLinkingTargets.isEmpty() || m_graph.m_blocks[m_inlineStackTop->m_caller->m_blockLinkingTargets.last()]->bytecodeBegin < nextOffset); @@ -1308,6 +1349,8 @@ bool ByteCodeParser::parseBlock(unsigned limit) } while (true) { + m_currentProfilingIndex = m_currentIndex; + // Don't extend over jump destinations. if (m_currentIndex == limit) { // Ordinarily we want to plant a jump. But refuse to do this if the block is @@ -1680,6 +1723,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_method_check: { + m_currentProfilingIndex += OPCODE_LENGTH(op_method_check); Instruction* getInstruction = currentInstruction + OPCODE_LENGTH(op_method_check); PredictedType prediction = getPrediction(); @@ -1691,23 +1735,26 @@ bool ByteCodeParser::parseBlock(unsigned limit) // Check if the method_check was monomorphic. If so, emit a CheckXYZMethod // node, which is a lot more efficient. - StructureStubInfo& stubInfo = m_inlineStackTop->m_profiledBlock->getStubInfo(m_currentIndex); - MethodCallLinkInfo& methodCall = m_inlineStackTop->m_profiledBlock->getMethodCallLinkInfo(m_currentIndex); + GetByIdStatus getByIdStatus = GetByIdStatus::computeFor( + m_inlineStackTop->m_profiledBlock, + m_currentIndex, + m_codeBlock->identifier(identifier)); + MethodCallLinkStatus methodCallStatus = MethodCallLinkStatus::computeFor( + m_inlineStackTop->m_profiledBlock, m_currentIndex); - if (methodCall.seen - && !!methodCall.cachedStructure - && !stubInfo.seen + if (methodCallStatus.isSet() + && !getByIdStatus.isSet() && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { // It's monomorphic as far as we can tell, since the method_check was linked // but the slow path (i.e. the normal get_by_id) never fired. - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCall.cachedStructure.get())), base); - if (methodCall.cachedPrototype.get() != m_inlineStackTop->m_profiledBlock->globalObject()->methodCallDummy()) - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCall.cachedPrototypeStructure.get())), cellConstant(methodCall.cachedPrototype.get())); + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.structure())), base); + if (methodCallStatus.needsPrototypeCheck()) + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.prototypeStructure())), cellConstant(methodCallStatus.prototype())); - set(getInstruction[1].u.operand, cellConstant(methodCall.cachedFunction.get())); + set(getInstruction[1].u.operand, cellConstant(methodCallStatus.function())); } else - set(getInstruction[1].u.operand, addToGraph(GetById, OpInfo(identifier), OpInfo(prediction), base)); + set(getInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifier), OpInfo(prediction), base)); m_currentIndex += OPCODE_LENGTH(op_method_check) + OPCODE_LENGTH(op_get_by_id); continue; @@ -1737,178 +1784,109 @@ bool ByteCodeParser::parseBlock(unsigned limit) unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; Identifier identifier = m_codeBlock->identifier(identifierNumber); - StructureStubInfo& stubInfo = m_inlineStackTop->m_profiledBlock->getStubInfo(m_currentIndex); + GetByIdStatus getByIdStatus = GetByIdStatus::computeFor( + m_inlineStackTop->m_profiledBlock, m_currentIndex, identifier); #if DFG_ENABLE(DEBUG_VERBOSE) - printf("Slow case count for GetById @%lu bc#%u: %u; exit profile: %d\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); + printf("Slow case count for GetById @%zu bc#%u: %u; exit profile: %d\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); #endif - size_t offset = notFound; - StructureSet structureSet; - if (stubInfo.seen - && !m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex) + if (getByIdStatus.isSimpleDirect() && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { - switch (stubInfo.accessType) { - case access_get_by_id_self: { - Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get(); - offset = structure->get(*m_globalData, identifier); - - if (offset != notFound) - structureSet.add(structure); - - if (offset != notFound) - ASSERT(structureSet.size()); - break; - } - - case access_get_by_id_self_list: { - PolymorphicAccessStructureList* list = stubInfo.u.getByIdProtoList.structureList; - unsigned size = stubInfo.u.getByIdProtoList.listSize; - for (unsigned i = 0; i < size; ++i) { - if (!list->list[i].isDirect) { - offset = notFound; - break; - } - - Structure* structure = list->list[i].base.get(); - if (structureSet.contains(structure)) - continue; - - size_t myOffset = structure->get(*m_globalData, identifier); - - if (myOffset == notFound) { - offset = notFound; - break; - } - - if (!i) - offset = myOffset; - else if (offset != myOffset) { - offset = notFound; - break; - } - - structureSet.add(structure); - } - - if (offset != notFound) - ASSERT(structureSet.size()); - break; - } - - default: - ASSERT(offset == notFound); - break; - } - } - - if (offset != notFound) { - ASSERT(structureSet.size()); + ASSERT(getByIdStatus.structureSet().size()); // The implementation of GetByOffset does not know to terminate speculative // execution if it doesn't have a prediction, so we do it manually. if (prediction == PredictNone) addToGraph(ForceOSRExit); - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structureSet)), base); + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base); set(currentInstruction[1].u.operand, addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), addToGraph(GetPropertyStorage, base))); StorageAccessData storageAccessData; - storageAccessData.offset = offset; + storageAccessData.offset = getByIdStatus.offset(); storageAccessData.identifierNumber = identifierNumber; m_graph.m_storageAccessData.append(storageAccessData); } else - set(currentInstruction[1].u.operand, addToGraph(GetById, OpInfo(identifierNumber), OpInfo(prediction), base)); + set(currentInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifierNumber), OpInfo(prediction), base)); NEXT_OPCODE(op_get_by_id); } - case op_put_by_id: { NodeIndex value = get(currentInstruction[3].u.operand); NodeIndex base = get(currentInstruction[1].u.operand); unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; bool direct = currentInstruction[8].u.operand; - StructureStubInfo& stubInfo = m_inlineStackTop->m_profiledBlock->getStubInfo(m_currentIndex); - if (!stubInfo.seen) + PutByIdStatus putByIdStatus = PutByIdStatus::computeFor( + m_inlineStackTop->m_profiledBlock, + m_currentIndex, + m_codeBlock->identifier(identifierNumber)); + if (!putByIdStatus.isSet()) addToGraph(ForceOSRExit); - bool alreadyGenerated = false; + bool hasExitSite = m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache); #if DFG_ENABLE(DEBUG_VERBOSE) - printf("Slow case count for PutById @%lu bc#%u: %u; exit profile: %d\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); + printf("Slow case count for PutById @%zu bc#%u: %u; exit profile: %d\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); #endif - if (stubInfo.seen - && !m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex) - && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { - switch (stubInfo.accessType) { - case access_put_by_id_replace: { - Structure* structure = stubInfo.u.putByIdReplace.baseObjectStructure.get(); - Identifier identifier = m_codeBlock->identifier(identifierNumber); - size_t offset = structure->get(*m_globalData, identifier); - - if (offset != notFound) { - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), base); - addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value); - - StorageAccessData storageAccessData; - storageAccessData.offset = offset; - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); - - alreadyGenerated = true; - } - break; - } - - case access_put_by_id_transition_normal: - case access_put_by_id_transition_direct: { - Structure* previousStructure = stubInfo.u.putByIdTransition.previousStructure.get(); - Structure* newStructure = stubInfo.u.putByIdTransition.structure.get(); - - if (previousStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity()) - break; - - StructureChain* structureChain = stubInfo.u.putByIdTransition.chain.get(); - - Identifier identifier = m_codeBlock->identifier(identifierNumber); - size_t offset = newStructure->get(*m_globalData, identifier); + if (!hasExitSite && putByIdStatus.isSimpleReplace()) { + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base); + addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value); + + StorageAccessData storageAccessData; + storageAccessData.offset = putByIdStatus.offset(); + storageAccessData.identifierNumber = identifierNumber; + m_graph.m_storageAccessData.append(storageAccessData); + } else if (!hasExitSite + && putByIdStatus.isSimpleTransition() + && putByIdStatus.oldStructure()->propertyStorageCapacity() == putByIdStatus.newStructure()->propertyStorageCapacity() + && structureChainIsStillValid( + direct, + putByIdStatus.oldStructure(), + putByIdStatus.structureChain())) { + + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base); + if (!direct) { + if (!putByIdStatus.oldStructure()->storedPrototype().isNull()) + addToGraph( + CheckStructure, + OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure()->storedPrototype().asCell()->structure())), + cellConstant(putByIdStatus.oldStructure()->storedPrototype().asCell())); - if (offset != notFound && structureChainIsStillValid(direct, previousStructure, structureChain)) { - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(previousStructure)), base); - if (!direct) { - if (!previousStructure->storedPrototype().isNull()) - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(previousStructure->storedPrototype().asCell()->structure())), cellConstant(previousStructure->storedPrototype().asCell())); - - for (WriteBarrier<Structure>* it = structureChain->head(); *it; ++it) { - JSValue prototype = (*it)->storedPrototype(); - if (prototype.isNull()) - continue; - ASSERT(prototype.isCell()); - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(prototype.asCell()->structure())), cellConstant(prototype.asCell())); - } - } - addToGraph(PutStructure, OpInfo(m_graph.addStructureTransitionData(StructureTransitionData(previousStructure, newStructure))), base); - - addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value); - - StorageAccessData storageAccessData; - storageAccessData.offset = offset; - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); - - alreadyGenerated = true; + for (WriteBarrier<Structure>* it = putByIdStatus.structureChain()->head(); *it; ++it) { + JSValue prototype = (*it)->storedPrototype(); + if (prototype.isNull()) + continue; + ASSERT(prototype.isCell()); + addToGraph( + CheckStructure, + OpInfo(m_graph.addStructureSet(prototype.asCell()->structure())), + cellConstant(prototype.asCell())); } - break; - } - - default: - break; } - } - - if (!alreadyGenerated) { + addToGraph( + PutStructure, + OpInfo( + m_graph.addStructureTransitionData( + StructureTransitionData( + putByIdStatus.oldStructure(), + putByIdStatus.newStructure()))), + base); + + addToGraph( + PutByOffset, + OpInfo(m_graph.m_storageAccessData.size()), + base, + addToGraph(GetPropertyStorage, base), + value); + + StorageAccessData storageAccessData; + storageAccessData.offset = putByIdStatus.offset(); + storageAccessData.identifierNumber = identifierNumber; + m_graph.m_storageAccessData.append(storageAccessData); + } else { if (direct) addToGraph(PutByIdDirect, OpInfo(identifierNumber), base, value); else @@ -2570,7 +2548,7 @@ void ByteCodeParser::parseCodeBlock() } else { OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(m_currentIndex, m_graph.size(), m_numArguments, m_numLocals)); #if DFG_ENABLE(DEBUG_VERBOSE) - printf("Creating basic block %p, #%lu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame)); + printf("Creating basic block %p, #%zu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame)); #endif m_currentBlock = block.get(); ASSERT(m_inlineStackTop->m_unlinkedBlocks.isEmpty() || m_graph.m_blocks[m_inlineStackTop->m_unlinkedBlocks.last().m_blockIndex]->bytecodeBegin < m_currentIndex); @@ -2620,6 +2598,9 @@ bool ByteCodeParser::parse() #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) printf("Processing local variable phis.\n"); #endif + + m_currentProfilingIndex = m_currentIndex; + processPhiStack<LocalPhiStack>(); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) printf("Processing argument phis.\n"); diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h new file mode 100644 index 000000000..3481f99e8 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h @@ -0,0 +1,548 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 DFGCCallHelpers_h +#define DFGCCallHelpers_h + +#include <wtf/Platform.h> + +#if ENABLE(DFG_JIT) + +#include "DFGAssemblyHelpers.h" +#include "DFGGPRInfo.h" + +namespace JSC { namespace DFG { + +class CCallHelpers : public AssemblyHelpers { +public: + CCallHelpers(JSGlobalData* globalData, CodeBlock* codeBlock) + : AssemblyHelpers(globalData, codeBlock) + { + } + + // These methods used to sort arguments into the correct registers. + // On X86 we use cdecl calling conventions, which pass all arguments on the + // stack. On other architectures we may need to sort values into the + // correct registers. +#if !NUMBER_OF_ARGUMENT_REGISTERS + unsigned m_callArgumentOffset; + void resetCallArguments() { m_callArgumentOffset = 0; } + + // These methods are using internally to implement the callOperation methods. + void addCallArgument(GPRReg value) + { + poke(value, m_callArgumentOffset++); + } + void addCallArgument(TrustedImm32 imm) + { + poke(imm, m_callArgumentOffset++); + } + void addCallArgument(TrustedImmPtr pointer) + { + poke(pointer, m_callArgumentOffset++); + } + void addCallArgument(FPRReg value) + { + storeDouble(value, Address(stackPointerRegister, m_callArgumentOffset * sizeof(void*))); + m_callArgumentOffset += sizeof(double) / sizeof(void*); + } + + ALWAYS_INLINE void setupArguments(FPRReg arg1) + { + resetCallArguments(); + addCallArgument(arg1); + } + + ALWAYS_INLINE void setupArguments(FPRReg arg1, FPRReg arg2) + { + resetCallArguments(); + addCallArgument(arg1); + addCallArgument(arg2); + } + + ALWAYS_INLINE void setupArguments(GPRReg arg1, GPRReg arg2) + { + resetCallArguments(); + addCallArgument(arg1); + addCallArgument(arg2); + } + + ALWAYS_INLINE void setupArgumentsExecState() + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImmPtr arg3) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, TrustedImmPtr arg3) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImmPtr arg3) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + addCallArgument(arg4); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + addCallArgument(arg4); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, TrustedImm32 arg4) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + addCallArgument(arg4); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, GPRReg arg3, GPRReg arg4) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + addCallArgument(arg4); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + addCallArgument(arg4); + addCallArgument(arg5); + } +#endif // !NUMBER_OF_ARGUMENT_REGISTERS + // These methods are suitable for any calling convention that provides for + // at least 4 argument registers, e.g. X86_64, ARMv7. +#if NUMBER_OF_ARGUMENT_REGISTERS >= 4 + template<GPRReg destA, GPRReg destB> + void setupTwoStubArgs(GPRReg srcA, GPRReg srcB) + { + // Assuming that srcA != srcB, there are 7 interesting states the registers may be in: + // (1) both are already in arg regs, the right way around. + // (2) both are already in arg regs, the wrong way around. + // (3) neither are currently in arg registers. + // (4) srcA in in its correct reg. + // (5) srcA in in the incorrect reg. + // (6) srcB in in its correct reg. + // (7) srcB in in the incorrect reg. + // + // The trivial approach is to simply emit two moves, to put srcA in place then srcB in + // place (the MacroAssembler will omit redundant moves). This apporach will be safe in + // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2 + // (requires a swap) and 7 (must move srcB first, to avoid trampling.) + + if (srcB != destA) { + // Handle the easy cases - two simple moves. + move(srcA, destA); + move(srcB, destB); + } else if (srcA != destB) { + // Handle the non-swap case - just put srcB in place first. + move(srcB, destB); + move(srcA, destA); + } else + swap(destA, destB); + } +#if CPU(X86_64) + template<FPRReg destA, FPRReg destB> + void setupTwoStubArgs(FPRReg srcA, FPRReg srcB) + { + // Assuming that srcA != srcB, there are 7 interesting states the registers may be in: + // (1) both are already in arg regs, the right way around. + // (2) both are already in arg regs, the wrong way around. + // (3) neither are currently in arg registers. + // (4) srcA in in its correct reg. + // (5) srcA in in the incorrect reg. + // (6) srcB in in its correct reg. + // (7) srcB in in the incorrect reg. + // + // The trivial approach is to simply emit two moves, to put srcA in place then srcB in + // place (the MacroAssembler will omit redundant moves). This apporach will be safe in + // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2 + // (requires a swap) and 7 (must move srcB first, to avoid trampling.) + + if (srcB != destA) { + // Handle the easy cases - two simple moves. + moveDouble(srcA, destA); + moveDouble(srcB, destB); + return; + } + + if (srcA != destB) { + // Handle the non-swap case - just put srcB in place first. + moveDouble(srcB, destB); + moveDouble(srcA, destA); + return; + } + + ASSERT(srcB == destA && srcA == destB); + // Need to swap; pick a temporary register. + FPRReg temp; + if (destA != FPRInfo::argumentFPR3 && destA != FPRInfo::argumentFPR3) + temp = FPRInfo::argumentFPR3; + else if (destA != FPRInfo::argumentFPR2 && destA != FPRInfo::argumentFPR2) + temp = FPRInfo::argumentFPR2; + else { + ASSERT(destA != FPRInfo::argumentFPR1 && destA != FPRInfo::argumentFPR1); + temp = FPRInfo::argumentFPR1; + } + moveDouble(destA, temp); + moveDouble(destB, destA); + moveDouble(temp, destB); + } +#endif + void setupStubArguments(GPRReg arg1, GPRReg arg2) + { + setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2); + } + void setupStubArguments(GPRReg arg1, GPRReg arg2, GPRReg arg3) + { + // If neither of arg2/arg3 are in our way, then we can move arg1 into place. + // Then we can use setupTwoStubArgs to fix arg2/arg3. + if (arg2 != GPRInfo::argumentGPR1 && arg3 != GPRInfo::argumentGPR1) { + move(arg1, GPRInfo::argumentGPR1); + setupTwoStubArgs<GPRInfo::argumentGPR2, GPRInfo::argumentGPR3>(arg2, arg3); + return; + } + + // If neither of arg1/arg3 are in our way, then we can move arg2 into place. + // Then we can use setupTwoStubArgs to fix arg1/arg3. + if (arg1 != GPRInfo::argumentGPR2 && arg3 != GPRInfo::argumentGPR2) { + move(arg2, GPRInfo::argumentGPR2); + setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3>(arg1, arg3); + return; + } + + // If neither of arg1/arg2 are in our way, then we can move arg3 into place. + // Then we can use setupTwoStubArgs to fix arg1/arg2. + if (arg1 != GPRInfo::argumentGPR3 && arg2 != GPRInfo::argumentGPR3) { + move(arg3, GPRInfo::argumentGPR3); + setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2); + return; + } + + // If we get here, we haven't been able to move any of arg1/arg2/arg3. + // Since all three are blocked, then all three must already be in the argument register. + // But are they in the right ones? + + // First, ensure arg1 is in place. + if (arg1 != GPRInfo::argumentGPR1) { + swap(arg1, GPRInfo::argumentGPR1); + + // If arg1 wasn't in argumentGPR1, one of arg2/arg3 must be. + ASSERT(arg2 == GPRInfo::argumentGPR1 || arg3 == GPRInfo::argumentGPR1); + // If arg2 was in argumentGPR1 it no longer is (due to the swap). + // Otherwise arg3 must have been. Mark him as moved. + if (arg2 == GPRInfo::argumentGPR1) + arg2 = arg1; + else + arg3 = arg1; + } + + // Either arg2 & arg3 need swapping, or we're all done. + ASSERT((arg2 == GPRInfo::argumentGPR2 || arg3 == GPRInfo::argumentGPR3) + || (arg2 == GPRInfo::argumentGPR3 || arg3 == GPRInfo::argumentGPR2)); + + if (arg2 != GPRInfo::argumentGPR2) + swap(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3); + } + +#if CPU(X86_64) + ALWAYS_INLINE void setupArguments(FPRReg arg1) + { + moveDouble(arg1, FPRInfo::argumentFPR0); + } + + ALWAYS_INLINE void setupArguments(FPRReg arg1, FPRReg arg2) + { + setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2); + } +#else + ALWAYS_INLINE void setupArguments(FPRReg arg1) + { + assembler().vmov(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, arg1); + } + + ALWAYS_INLINE void setupArguments(FPRReg arg1, FPRReg arg2) + { + assembler().vmov(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, arg1); + assembler().vmov(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, arg2); + } +#endif + + ALWAYS_INLINE void setupArguments(GPRReg arg1, GPRReg arg2) + { + setupTwoStubArgs<GPRInfo::argumentGPR0, GPRInfo::argumentGPR1>(arg1, arg2); + } + + ALWAYS_INLINE void setupArgumentsExecState() + { + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1) + { + move(arg1, GPRInfo::argumentGPR1); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1) + { + move(arg1, GPRInfo::argumentGPR1); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2) + { + setupStubArguments(arg1, arg2); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2) + { + move(arg1, GPRInfo::argumentGPR1); + move(arg2, GPRInfo::argumentGPR2); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2) + { + move(arg2, GPRInfo::argumentGPR2); // Move this first, so setting arg1 does not trample! + move(arg1, GPRInfo::argumentGPR1); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2) + { + move(arg1, GPRInfo::argumentGPR1); + move(arg2, GPRInfo::argumentGPR2); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2) + { + move(arg1, GPRInfo::argumentGPR1); + move(arg2, GPRInfo::argumentGPR2); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3) + { + setupStubArguments(arg1, arg2, arg3); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3) + { + setupStubArguments(arg1, arg2); + move(arg3, GPRInfo::argumentGPR3); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, TrustedImmPtr arg3) + { + move(arg1, GPRInfo::argumentGPR1); + move(arg2, GPRInfo::argumentGPR2); + move(arg3, GPRInfo::argumentGPR3); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImmPtr arg3) + { + move(arg1, GPRInfo::argumentGPR1); + move(arg2, GPRInfo::argumentGPR2); + move(arg3, GPRInfo::argumentGPR3); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImmPtr arg3) + { + setupStubArguments(arg1, arg2); + move(arg3, GPRInfo::argumentGPR3); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, GPRReg arg3) + { + move(arg1, GPRInfo::argumentGPR1); + move(arg2, GPRInfo::argumentGPR2); + move(arg3, GPRInfo::argumentGPR3); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + +#endif // NUMBER_OF_ARGUMENT_REGISTERS >= 4 + // These methods are suitable for any calling convention that provides for + // exactly 4 argument registers, e.g. ARMv7. +#if NUMBER_OF_ARGUMENT_REGISTERS == 4 + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4) + { + poke(arg4); + setupArgumentsWithExecState(arg1, arg2, arg3); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, TrustedImm32 arg4) + { + poke(arg4); + setupArgumentsWithExecState(arg1, arg2, arg3); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, GPRReg arg3, GPRReg arg4) + { + poke(arg4); + setupArgumentsWithExecState(arg1, arg2, arg3); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4) + { + poke(arg4); + setupArgumentsWithExecState(arg1, arg2, arg3); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5) + { + poke(arg5, 1); + poke(arg4); + setupArgumentsWithExecState(arg1, arg2, arg3); + } +#endif // NUMBER_OF_ARGUMENT_REGISTERS == 4 + + void setupResults(GPRReg destA, GPRReg destB) + { + GPRReg srcA = GPRInfo::returnValueGPR; + GPRReg srcB = GPRInfo::returnValueGPR2; + + if (srcB != destA) { + // Handle the easy cases - two simple moves. + move(srcA, destA); + move(srcB, destB); + } else if (srcA != destB) { + // Handle the non-swap case - just put srcB in place first. + move(srcB, destB); + move(srcA, destA); + } else + swap(destA, destB); + } +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGCCallHelpers_h + diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp index 2143fbc19..27a0dab75 100644 --- a/Source/JavaScriptCore/dfg/DFGDriver.cpp +++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp @@ -35,7 +35,7 @@ namespace JSC { namespace DFG { enum CompileMode { CompileFunction, CompileOther }; -inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr* jitCodeWithArityCheck) +inline bool compile(CompileMode compileMode, JSGlobalData& globalData, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr* jitCodeWithArityCheck) { SamplingRegion samplingRegion("DFG Compilation (Driver)"); @@ -47,17 +47,16 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo fprintf(stderr, "DFG compiling code block %p(%p), number of instructions = %u.\n", codeBlock, codeBlock->alternative(), codeBlock->instructionCount()); #endif - JSGlobalData* globalData = &exec->globalData(); Graph dfg; - if (!parse(dfg, globalData, codeBlock)) + if (!parse(dfg, &globalData, codeBlock)) return false; if (compileMode == CompileFunction) dfg.predictArgumentTypes(codeBlock); - propagate(dfg, globalData, codeBlock); + propagate(dfg, &globalData, codeBlock); - JITCompiler dataFlowJIT(globalData, dfg, codeBlock); + JITCompiler dataFlowJIT(&globalData, dfg, codeBlock); if (compileMode == CompileFunction) { ASSERT(jitCodeWithArityCheck); @@ -72,14 +71,14 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo return true; } -bool tryCompile(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode) +bool tryCompile(JSGlobalData& globalData, CodeBlock* codeBlock, JITCode& jitCode) { - return compile(CompileOther, exec, codeBlock, jitCode, 0); + return compile(CompileOther, globalData, codeBlock, jitCode, 0); } -bool tryCompileFunction(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck) +bool tryCompileFunction(JSGlobalData& globalData, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck) { - return compile(CompileFunction, exec, codeBlock, jitCode, &jitCodeWithArityCheck); + return compile(CompileFunction, globalData, codeBlock, jitCode, &jitCodeWithArityCheck); } } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGDriver.h b/Source/JavaScriptCore/dfg/DFGDriver.h index dad45f32e..639b13f7a 100644 --- a/Source/JavaScriptCore/dfg/DFGDriver.h +++ b/Source/JavaScriptCore/dfg/DFGDriver.h @@ -30,19 +30,19 @@ namespace JSC { -class ExecState; class CodeBlock; class JITCode; +class JSGlobalData; class MacroAssemblerCodePtr; namespace DFG { #if ENABLE(DFG_JIT) -bool tryCompile(ExecState*, CodeBlock*, JITCode&); -bool tryCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr& jitCodeWithArityCheck); +bool tryCompile(JSGlobalData&, CodeBlock*, JITCode&); +bool tryCompileFunction(JSGlobalData&, CodeBlock*, JITCode&, MacroAssemblerCodePtr& jitCodeWithArityCheck); #else -inline bool tryCompile(ExecState*, CodeBlock*, JITCode&) { return false; } -inline bool tryCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr&) { return false; } +inline bool tryCompile(JSGlobalData&, CodeBlock*, JITCode&) { return false; } +inline bool tryCompileFunction(JSGlobalData&, CodeBlock*, JITCode&, MacroAssemblerCodePtr&) { return false; } #endif } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp index 2a3e23040..e01bea195 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.cpp +++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp @@ -261,10 +261,10 @@ void Graph::dump(NodeIndex nodeIndex, CodeBlock* codeBlock) if (!skipped) { if (node.hasVariableAccessData()) printf(" predicting %s, double ratio %lf%s", predictionToString(node.variableAccessData()->prediction()), node.variableAccessData()->doubleVoteRatio(), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : ""); - else if (node.hasVarNumber()) - printf(" predicting %s", predictionToString(getGlobalVarPrediction(node.varNumber()))); else if (node.hasHeapPrediction()) printf(" predicting %s", predictionToString(node.getHeapPrediction())); + else if (node.hasVarNumber()) + printf(" predicting %s", predictionToString(getGlobalVarPrediction(node.varNumber()))); } printf("\n"); @@ -353,7 +353,7 @@ void Graph::predictArgumentTypes(CodeBlock* codeBlock) at(m_arguments[arg]).variableAccessData()->predict(profile->computeUpdatedPrediction()); #if DFG_ENABLE(DEBUG_VERBOSE) - printf("Argument [%lu] prediction: %s\n", arg, predictionToString(at(m_arguments[arg]).variableAccessData()->prediction())); + printf("Argument [%zu] prediction: %s\n", arg, predictionToString(at(m_arguments[arg]).variableAccessData()->prediction())); #endif } } diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index fb729063d..d3f16a0f4 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -137,6 +137,26 @@ public: return predictionFromValue(node.valueOfJSConstant(codeBlock)); } + bool addShouldSpeculateInteger(Node& add, CodeBlock* codeBlock) + { + ASSERT(add.op == ValueAdd || add.op == ArithAdd || add.op == ArithSub); + + Node& left = at(add.child1()); + Node& right = at(add.child2()); + + if (left.hasConstant()) + return addImmediateShouldSpeculateInteger(codeBlock, add, right, left); + if (right.hasConstant()) + return addImmediateShouldSpeculateInteger(codeBlock, add, left, right); + + return Node::shouldSpeculateInteger(left, right) && add.canSpeculateInteger(); + } + + bool addShouldSpeculateInteger(NodeIndex nodeIndex, CodeBlock* codeBlock) + { + return addShouldSpeculateInteger(at(nodeIndex), codeBlock); + } + // Helper methods to check nodes for constants. bool isConstant(NodeIndex nodeIndex) { @@ -223,8 +243,7 @@ public: Node& node = at(nodeIndex); - switch (node.op) { - case GetLocal: { + if (node.op == GetLocal) { if (!operandIsArgument(node.local())) return 0; int argument = operandToArgument(node.local()); @@ -233,21 +252,10 @@ public: return profiledBlock->valueProfileForArgument(argument); } - // Nodes derives from calls need special handling because the value profile is - // associated with the op_call_put_result instruction. - case Call: - case Construct: - case ArrayPop: - case ArrayPush: { - ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); - return profiledBlock->valueProfileForBytecodeOffset(node.codeOrigin.bytecodeIndex + OPCODE_LENGTH(op_call)); - } - - default: - if (node.hasHeapPrediction()) - return profiledBlock->valueProfileForBytecodeOffset(node.codeOrigin.bytecodeIndex); - return 0; - } + if (node.hasHeapPrediction()) + return profiledBlock->valueProfileForBytecodeOffset(node.codeOrigin.bytecodeIndexForValueProfile()); + + return 0; } Vector< OwnPtr<BasicBlock> , 8> m_blocks; @@ -263,6 +271,28 @@ public: unsigned m_parameterSlots; private: + bool addImmediateShouldSpeculateInteger(CodeBlock* codeBlock, Node& add, Node& variable, Node& immediate) + { + ASSERT(immediate.hasConstant()); + + JSValue immediateValue = immediate.valueOfJSConstant(codeBlock); + if (!immediateValue.isNumber()) + return false; + + if (!variable.shouldSpeculateInteger()) + return false; + + if (immediateValue.isInt32()) + return add.canSpeculateInteger(); + + double doubleImmediate = immediateValue.asDouble(); + const double twoToThe48 = 281474976710656.0; + if (doubleImmediate < -twoToThe48 || doubleImmediate > twoToThe48) + return false; + + return nodeCanTruncateInteger(add.arithNodeFlags()); + } + // When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa. void refChildren(NodeIndex); void derefChildren(NodeIndex); diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp index 593e4d930..ac5f314a1 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp @@ -116,7 +116,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer) { // Link the code, populate data in CodeBlock data structures. #if DFG_ENABLE(DEBUG_VERBOSE) - fprintf(stderr, "JIT code for %p start at [%p, %p). Size = %lu.\n", m_codeBlock, linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize(), linkBuffer.debugSize()); + fprintf(stderr, "JIT code for %p start at [%p, %p). Size = %zu.\n", m_codeBlock, linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize(), linkBuffer.debugSize()); #endif // Link all calls out from the JIT code to their respective functions. @@ -151,6 +151,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer) unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_exceptionChecks[i].m_call); codeOrigins[j].codeOrigin = record.m_codeOrigin; codeOrigins[j].callReturnOffset = returnAddressOffset; + record.m_token.assertCodeOriginIndex(j); j++; } } @@ -160,6 +161,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer) for (unsigned i = 0; i < m_propertyAccesses.size(); ++i) { StructureStubInfo& info = m_codeBlock->structureStubInfo(i); CodeLocationCall callReturnLocation = linkBuffer.locationOf(m_propertyAccesses[i].m_functionCall); + info.codeOrigin = m_propertyAccesses[i].m_codeOrigin; info.callReturnLocation = callReturnLocation; info.deltaCheckImmToCall = differenceBetweenCodePtr(linkBuffer.locationOf(m_propertyAccesses[i].m_deltaCheckImmToCall), callReturnLocation); info.deltaCallToStructCheck = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_deltaCallToStructCheck)); @@ -179,6 +181,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer) info.valueGPR = m_propertyAccesses[i].m_valueGPR; #endif info.scratchGPR = m_propertyAccesses[i].m_scratchGPR; + info.registersFlushed = m_propertyAccesses[i].m_registerMode == PropertyAccessRecord::RegistersFlushed; } m_codeBlock->setNumberOfCallLinkInfos(m_jsCalls.size()); @@ -209,7 +212,7 @@ void JITCompiler::compile(JITCode& entry) SpeculativeJIT speculative(*this); compileBody(speculative); - LinkBuffer linkBuffer(*m_globalData, this); + LinkBuffer linkBuffer(*m_globalData, this, m_codeBlock); link(linkBuffer); speculative.linkOSREntries(linkBuffer); @@ -269,7 +272,7 @@ void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi // === Link === - LinkBuffer linkBuffer(*m_globalData, this); + LinkBuffer linkBuffer(*m_globalData, this, m_codeBlock); link(linkBuffer); speculative.linkOSREntries(linkBuffer); diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h index de0475a56..451bee6ca 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h @@ -31,7 +31,7 @@ #include <assembler/LinkBuffer.h> #include <assembler/MacroAssembler.h> #include <bytecode/CodeBlock.h> -#include <dfg/DFGAssemblyHelpers.h> +#include <dfg/DFGCCallHelpers.h> #include <dfg/DFGFPRInfo.h> #include <dfg/DFGGPRInfo.h> #include <dfg/DFGGraph.h> @@ -70,37 +70,76 @@ struct CallLinkRecord { FunctionPtr m_function; }; +class CallBeginToken { +public: + CallBeginToken() +#if !ASSERT_DISABLED + : m_codeOriginIndex(UINT_MAX) +#endif + { + } + + explicit CallBeginToken(unsigned codeOriginIndex) +#if !ASSERT_DISABLED + : m_codeOriginIndex(codeOriginIndex) +#endif + { + UNUSED_PARAM(codeOriginIndex); + } + + void assertCodeOriginIndex(unsigned codeOriginIndex) const + { + ASSERT_UNUSED(codeOriginIndex, codeOriginIndex < UINT_MAX); + ASSERT_UNUSED(codeOriginIndex, codeOriginIndex == m_codeOriginIndex); + } + + void assertNoCodeOriginIndex() const + { + ASSERT(m_codeOriginIndex == UINT_MAX); + } +private: +#if !ASSERT_DISABLED + unsigned m_codeOriginIndex; +#endif +}; + // === CallExceptionRecord === // // A record of a call out from JIT code that might throw an exception. // Calls that might throw an exception also record the Jump taken on exception // (unset if not present) and code origin used to recover handler/source info. struct CallExceptionRecord { - CallExceptionRecord(MacroAssembler::Call call, CodeOrigin codeOrigin) + CallExceptionRecord(MacroAssembler::Call call, CodeOrigin codeOrigin, CallBeginToken token) : m_call(call) , m_codeOrigin(codeOrigin) + , m_token(token) { } - CallExceptionRecord(MacroAssembler::Call call, MacroAssembler::Jump exceptionCheck, CodeOrigin codeOrigin) + CallExceptionRecord(MacroAssembler::Call call, MacroAssembler::Jump exceptionCheck, CodeOrigin codeOrigin, CallBeginToken token) : m_call(call) , m_exceptionCheck(exceptionCheck) , m_codeOrigin(codeOrigin) + , m_token(token) { } MacroAssembler::Call m_call; MacroAssembler::Jump m_exceptionCheck; CodeOrigin m_codeOrigin; + CallBeginToken m_token; }; struct PropertyAccessRecord { + enum RegisterMode { RegistersFlushed, RegistersInUse }; + #if USE(JSVALUE64) - PropertyAccessRecord(MacroAssembler::DataLabelPtr deltaCheckImmToCall, MacroAssembler::Call functionCall, MacroAssembler::Jump deltaCallToStructCheck, MacroAssembler::DataLabelCompact deltaCallToLoadOrStore, MacroAssembler::Label deltaCallToSlowCase, MacroAssembler::Label deltaCallToDone, int8_t baseGPR, int8_t valueGPR, int8_t scratchGPR) + PropertyAccessRecord(CodeOrigin codeOrigin, MacroAssembler::DataLabelPtr deltaCheckImmToCall, MacroAssembler::Call functionCall, MacroAssembler::Jump deltaCallToStructCheck, MacroAssembler::DataLabelCompact deltaCallToLoadOrStore, MacroAssembler::Label deltaCallToSlowCase, MacroAssembler::Label deltaCallToDone, int8_t baseGPR, int8_t valueGPR, int8_t scratchGPR, RegisterMode registerMode = RegistersInUse) #elif USE(JSVALUE32_64) - PropertyAccessRecord(MacroAssembler::DataLabelPtr deltaCheckImmToCall, MacroAssembler::Call functionCall, MacroAssembler::Jump deltaCallToStructCheck, MacroAssembler::DataLabelCompact deltaCallToTagLoadOrStore, MacroAssembler::DataLabelCompact deltaCallToPayloadLoadOrStore, MacroAssembler::Label deltaCallToSlowCase, MacroAssembler::Label deltaCallToDone, int8_t baseGPR, int8_t valueTagGPR, int8_t valueGPR, int8_t scratchGPR) + PropertyAccessRecord(CodeOrigin codeOrigin, MacroAssembler::DataLabelPtr deltaCheckImmToCall, MacroAssembler::Call functionCall, MacroAssembler::Jump deltaCallToStructCheck, MacroAssembler::DataLabelCompact deltaCallToTagLoadOrStore, MacroAssembler::DataLabelCompact deltaCallToPayloadLoadOrStore, MacroAssembler::Label deltaCallToSlowCase, MacroAssembler::Label deltaCallToDone, int8_t baseGPR, int8_t valueTagGPR, int8_t valueGPR, int8_t scratchGPR, RegisterMode registerMode = RegistersInUse) #endif - : m_deltaCheckImmToCall(deltaCheckImmToCall) + : m_codeOrigin(codeOrigin) + , m_deltaCheckImmToCall(deltaCheckImmToCall) , m_functionCall(functionCall) , m_deltaCallToStructCheck(deltaCallToStructCheck) #if USE(JSVALUE64) @@ -117,9 +156,11 @@ struct PropertyAccessRecord { #endif , m_valueGPR(valueGPR) , m_scratchGPR(scratchGPR) + , m_registerMode(registerMode) { } + CodeOrigin m_codeOrigin; MacroAssembler::DataLabelPtr m_deltaCheckImmToCall; MacroAssembler::Call m_functionCall; MacroAssembler::Jump m_deltaCallToStructCheck; @@ -137,6 +178,7 @@ struct PropertyAccessRecord { #endif int8_t m_valueGPR; int8_t m_scratchGPR; + RegisterMode m_registerMode; }; // === JITCompiler === @@ -147,11 +189,12 @@ struct PropertyAccessRecord { // relationship). The JITCompiler holds references to information required during // compilation, and also records information used in linking (e.g. a list of all // call to be linked). -class JITCompiler : public AssemblyHelpers { +class JITCompiler : public CCallHelpers { public: JITCompiler(JSGlobalData* globalData, Graph& dfg, CodeBlock* codeBlock) - : AssemblyHelpers(globalData, codeBlock) + : CCallHelpers(globalData, codeBlock) , m_graph(dfg) + , m_currentCodeOriginIndex(0) { } @@ -160,11 +203,32 @@ public: // Accessors for properties. Graph& graph() { return m_graph; } + + // Just get a token for beginning a call. + CallBeginToken nextCallBeginToken(CodeOrigin codeOrigin) + { + if (!codeOrigin.inlineCallFrame) + return CallBeginToken(); + return CallBeginToken(m_currentCodeOriginIndex++); + } + + // Get a token for beginning a call, and set the current code origin index in + // the call frame. + CallBeginToken beginCall(CodeOrigin codeOrigin) + { + unsigned codeOriginIndex; + if (!codeOrigin.inlineCallFrame) + codeOriginIndex = UINT_MAX; + else + codeOriginIndex = m_currentCodeOriginIndex++; + store32(TrustedImm32(codeOriginIndex), tagFor(static_cast<VirtualRegister>(RegisterFile::ArgumentCount))); + return CallBeginToken(codeOriginIndex); + } // Notify the JIT of a call that does not require linking. - void notifyCall(Call functionCall, CodeOrigin codeOrigin) + void notifyCall(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token) { - m_exceptionChecks.append(CallExceptionRecord(functionCall, codeOrigin)); + m_exceptionChecks.append(CallExceptionRecord(functionCall, codeOrigin, token)); } // Add a call out from JIT code, without an exception check. @@ -176,25 +240,18 @@ public: } // Add a call out from JIT code, with an exception check. - Call addExceptionCheck(Call functionCall, CodeOrigin codeOrigin) + void addExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token) { move(TrustedImm32(m_exceptionChecks.size()), GPRInfo::nonPreservedNonReturnGPR); -#if USE(JSVALUE64) - Jump exceptionCheck = branchTestPtr(NonZero, AbsoluteAddress(&globalData()->exception)); -#elif USE(JSVALUE32_64) - Jump exceptionCheck = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&globalData()->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); -#endif - m_exceptionChecks.append(CallExceptionRecord(functionCall, exceptionCheck, codeOrigin)); - return functionCall; + m_exceptionChecks.append(CallExceptionRecord(functionCall, emitExceptionCheck(), codeOrigin, token)); } // Add a call out from JIT code, with a fast exception check that tests if the return value is zero. - Call addFastExceptionCheck(Call functionCall, CodeOrigin codeOrigin) + void addFastExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token) { move(TrustedImm32(m_exceptionChecks.size()), GPRInfo::nonPreservedNonReturnGPR); Jump exceptionCheck = branchTestPtr(Zero, GPRInfo::returnValueGPR); - m_exceptionChecks.append(CallExceptionRecord(functionCall, exceptionCheck, codeOrigin)); - return functionCall; + m_exceptionChecks.append(CallExceptionRecord(functionCall, exceptionCheck, codeOrigin, token)); } // Helper methods to check nodes for constants. @@ -325,6 +382,7 @@ private: Vector<PropertyAccessRecord, 4> m_propertyAccesses; Vector<JSCallRecord, 4> m_jsCalls; + unsigned m_currentCodeOriginIndex; }; } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index cb5be691c..7366c1c40 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -229,6 +229,7 @@ static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags) macro(PutByVal, NodeMustGenerate | NodeClobbersWorld) \ macro(PutByValAlias, NodeMustGenerate | NodeClobbersWorld) \ macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ + macro(GetByIdFlush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ macro(PutById, NodeMustGenerate | NodeClobbersWorld) \ macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \ macro(CheckStructure, NodeMustGenerate) \ @@ -244,6 +245,7 @@ static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags) macro(GetInt16ArrayLength, NodeResultInt32) \ macro(GetInt32ArrayLength, NodeResultInt32) \ macro(GetUint8ArrayLength, NodeResultInt32) \ + macro(GetUint8ClampedArrayLength, NodeResultInt32) \ macro(GetUint16ArrayLength, NodeResultInt32) \ macro(GetUint32ArrayLength, NodeResultInt32) \ macro(GetFloat32ArrayLength, NodeResultInt32) \ @@ -502,6 +504,7 @@ struct Node { { switch (op) { case GetById: + case GetByIdFlush: case PutById: case PutByIdDirect: case Resolve: @@ -718,6 +721,7 @@ struct Node { { switch (op) { case GetById: + case GetByIdFlush: case GetByVal: case Call: case Construct: @@ -960,6 +964,11 @@ struct Node { { return isUint8ArrayPrediction(prediction()); } + + bool shouldSpeculateUint8ClampedArray() + { + return isUint8ClampedArrayPrediction(prediction()); + } bool shouldSpeculateUint16Array() { diff --git a/Source/JavaScriptCore/dfg/DFGOSREntry.cpp b/Source/JavaScriptCore/dfg/DFGOSREntry.cpp index 4510ec7b9..cbcd1319a 100644 --- a/Source/JavaScriptCore/dfg/DFGOSREntry.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSREntry.cpp @@ -80,7 +80,7 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn for (size_t argument = 0; argument < entry->m_expectedValues.numberOfArguments(); ++argument) { if (argument >= exec->argumentCountIncludingThis()) { #if ENABLE(JIT_VERBOSE_OSR) - printf(" OSR failed because argument %lu was not passed, expected ", argument); + printf(" OSR failed because argument %zu was not passed, expected ", argument); entry->m_expectedValues.argument(argument).dump(stdout); printf(".\n"); #endif @@ -95,7 +95,7 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn if (!entry->m_expectedValues.argument(argument).validate(value)) { #if ENABLE(JIT_VERBOSE_OSR) - printf(" OSR failed because argument %lu is %s, expected ", argument, value.description()); + printf(" OSR failed because argument %zu is %s, expected ", argument, value.description()); entry->m_expectedValues.argument(argument).dump(stdout); printf(".\n"); #endif @@ -107,7 +107,7 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn if (entry->m_localsForcedDouble.get(local)) { if (!exec->registers()[local].jsValue().isNumber()) { #if ENABLE(JIT_VERBOSE_OSR) - printf(" OSR failed because variable %lu is %s, expected number.\n", local, exec->registers()[local].jsValue().description()); + printf(" OSR failed because variable %zu is %s, expected number.\n", local, exec->registers()[local].jsValue().description()); #endif return 0; } @@ -115,7 +115,7 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn } if (!entry->m_expectedValues.local(local).validate(exec->registers()[local].jsValue())) { #if ENABLE(JIT_VERBOSE_OSR) - printf(" OSR failed because variable %lu is %s, expected ", local, exec->registers()[local].jsValue().description()); + printf(" OSR failed because variable %zu is %s, expected ", local, exec->registers()[local].jsValue().description()); entry->m_expectedValues.local(local).dump(stdout); printf(".\n"); #endif diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp index 3da8189d1..1b88c4ffc 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp @@ -62,7 +62,7 @@ void compileOSRExit(ExecState* exec) exitCompiler.compileExit(exit, recovery); - LinkBuffer patchBuffer(*globalData, &jit); + LinkBuffer patchBuffer(*globalData, &jit, codeBlock); exit.m_code = patchBuffer.finalizeCode(); #if DFG_ENABLE(DEBUG_VERBOSE) diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp index 3d27e00e4..4e33d7b02 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp @@ -579,13 +579,13 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco AssemblyHelpers::Jump lowFailRate = m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, GPRInfo::regT1); // Reoptimize as soon as possible. - m_jit.store32(AssemblyHelpers::Imm32(Options::executionCounterValueForOptimizeNextInvocation), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfExecuteCounter())); + m_jit.store32(AssemblyHelpers::Imm32(Options::executionCounterValueForOptimizeNextInvocation), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter())); AssemblyHelpers::Jump doneAdjusting = m_jit.jump(); fewFails.link(&m_jit); lowFailRate.link(&m_jit); - m_jit.store32(AssemblyHelpers::Imm32(m_jit.baselineCodeBlock()->counterValueForOptimizeAfterLongWarmUp()), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfExecuteCounter())); + m_jit.store32(AssemblyHelpers::Imm32(m_jit.baselineCodeBlock()->counterValueForOptimizeAfterLongWarmUp()), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter())); doneAdjusting.link(&m_jit); diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp index c6f4a9ed4..98c891ac7 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp @@ -554,13 +554,13 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco AssemblyHelpers::Jump lowFailRate = m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, GPRInfo::regT1); // Reoptimize as soon as possible. - m_jit.store32(AssemblyHelpers::Imm32(Options::executionCounterValueForOptimizeNextInvocation), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfExecuteCounter())); + m_jit.store32(AssemblyHelpers::Imm32(Options::executionCounterValueForOptimizeNextInvocation), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter())); AssemblyHelpers::Jump doneAdjusting = m_jit.jump(); fewFails.link(&m_jit); lowFailRate.link(&m_jit); - m_jit.store32(AssemblyHelpers::Imm32(m_jit.baselineCodeBlock()->counterValueForOptimizeAfterLongWarmUp()), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfExecuteCounter())); + m_jit.store32(AssemblyHelpers::Imm32(m_jit.baselineCodeBlock()->counterValueForOptimizeAfterLongWarmUp()), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter())); doneAdjusting.link(&m_jit); diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index 2e6fd9276..569b4fe86 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -31,6 +31,7 @@ #include "CodeBlock.h" #include "DFGOSRExit.h" #include "DFGRepatch.h" +#include "GetterSetter.h" #include "InlineASM.h" #include "Interpreter.h" #include "JSByteArray.h" @@ -42,6 +43,7 @@ #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, register) \ asm( \ ".globl " SYMBOL_STRING(function) "\n" \ + HIDE_SYMBOL(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ "mov (%rsp), %" STRINGIZE(register) "\n" \ "jmp " SYMBOL_STRING_RELOCATION(function##WithReturnAddress) "\n" \ @@ -56,6 +58,7 @@ #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, offset) \ asm( \ ".globl " SYMBOL_STRING(function) "\n" \ + HIDE_SYMBOL(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ "mov (%esp), %eax\n" \ "mov %eax, " STRINGIZE(offset) "(%esp)\n" \ @@ -175,6 +178,9 @@ static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, template<bool strict> ALWAYS_INLINE static void DFG_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); JSValue value = JSValue::decode(encodedValue); @@ -193,10 +199,9 @@ ALWAYS_INLINE static void DFG_OPERATION operationPutByValInternal(ExecState* exe } } - JSGlobalData* globalData = &exec->globalData(); // Don't put to an object if toString throws an exception. - Identifier ident(exec, property.toString(exec)); + Identifier ident(exec, property.toString(exec)->value(exec)); if (!globalData->exception) { PutPropertySlot slot(strict); baseValue.put(exec, ident, value, slot); @@ -207,6 +212,9 @@ extern "C" { EncodedJSValue DFG_OPERATION operationConvertThis(ExecState* exec, EncodedJSValue encodedOp) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec)); } @@ -230,21 +238,33 @@ inline JSCell* createThis(ExecState* exec, JSCell* prototype, JSFunction* constr JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* prototype) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return createThis(exec, prototype, asFunction(exec->callee())); } JSCell* DFG_OPERATION operationCreateThisInlined(ExecState* exec, JSCell* prototype, JSCell* constructor) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return createThis(exec, prototype, static_cast<JSFunction*>(constructor)); } JSCell* DFG_OPERATION operationNewObject(ExecState* exec) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return constructEmptyObject(exec); } EncodedJSValue DFG_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue op1 = JSValue::decode(encodedOp1); JSValue op2 = JSValue::decode(encodedOp2); @@ -253,16 +273,16 @@ EncodedJSValue DFG_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue e EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue op1 = JSValue::decode(encodedOp1); JSValue op2 = JSValue::decode(encodedOp2); ASSERT(!op1.isNumber() || !op2.isNumber()); - if (op1.isString()) { - if (op2.isString()) - return JSValue::encode(jsString(exec, asString(op1), asString(op2))); - return JSValue::encode(jsString(exec, asString(op1), op2.toPrimitiveString(exec))); - } + if (op1.isString() && !op2.isObject()) + return JSValue::encode(jsString(exec, asString(op1), op2.toString(exec))); return JSValue::encode(jsAddSlowCase(exec, op1, op2)); } @@ -286,6 +306,9 @@ static inline EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t in EncodedJSValue DFG_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); @@ -305,12 +328,15 @@ EncodedJSValue DFG_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue e } } - Identifier ident(exec, property.toString(exec)); + Identifier ident(exec, property.toString(exec)->value(exec)); return JSValue::encode(baseValue.get(exec, ident)); } EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue property = JSValue::decode(encodedProperty); if (property.isUInt32()) @@ -325,12 +351,15 @@ EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState* exec, JSCell* base return JSValue::encode(result); } - Identifier ident(exec, property.toString(exec)); + Identifier ident(exec, property.toString(exec)->value(exec)); return JSValue::encode(JSValue(base).get(exec, ident)); } EncodedJSValue DFG_OPERATION operationGetById(ExecState* exec, EncodedJSValue base, Identifier* propertyName) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue baseValue = JSValue::decode(base); PropertySlot slot(baseValue); return JSValue::encode(baseValue.get(exec, *propertyName, slot)); @@ -339,6 +368,9 @@ EncodedJSValue DFG_OPERATION operationGetById(ExecState* exec, EncodedJSValue ba J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdBuildList); EncodedJSValue DFG_OPERATION operationGetByIdBuildListWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue baseValue = JSValue::decode(base); PropertySlot slot(baseValue); JSValue result = baseValue.get(exec, *propertyName, slot); @@ -352,6 +384,9 @@ EncodedJSValue DFG_OPERATION operationGetByIdBuildListWithReturnAddress(ExecStat J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdProtoBuildList); EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildListWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue baseValue = JSValue::decode(base); PropertySlot slot(baseValue); JSValue result = baseValue.get(exec, *propertyName, slot); @@ -365,6 +400,9 @@ EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildListWithReturnAddress(Exe J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdOptimize); EncodedJSValue DFG_OPERATION operationGetByIdOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue baseValue = JSValue::decode(base); PropertySlot slot(baseValue); JSValue result = baseValue.get(exec, *propertyName, slot); @@ -378,28 +416,65 @@ EncodedJSValue DFG_OPERATION operationGetByIdOptimizeWithReturnAddress(ExecState return JSValue::encode(result); } +EncodedJSValue DFG_OPERATION operationCallCustomGetter(ExecState* exec, JSCell* base, PropertySlot::GetValueFunc function, Identifier* ident) +{ + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + + return JSValue::encode(function(exec, asObject(base), *ident)); +} + +EncodedJSValue DFG_OPERATION operationCallGetter(ExecState* exec, JSCell* base, JSCell* value) +{ + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + + GetterSetter* getterSetter = asGetterSetter(value); + JSObject* getter = getterSetter->getter(); + if (!getter) + return JSValue::encode(jsUndefined()); + CallData callData; + CallType callType = getter->methodTable()->getCallData(getter, callData); + return JSValue::encode(call(exec, getter, callType, callData, asObject(base), ArgList())); +} + void DFG_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue); } void DFG_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue); } void DFG_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + operationPutByValInternal<true>(exec, JSValue::encode(cell), encodedProperty, encodedValue); } void DFG_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + operationPutByValInternal<false>(exec, JSValue::encode(cell), encodedProperty, encodedValue); } void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + // We should only get here if index is outside the existing vector. ASSERT(!array->canSetIndex(index)); JSArray::putByIndex(array, exec, index, JSValue::decode(encodedValue)); @@ -407,42 +482,65 @@ void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState* exec, JSArray* EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + array->push(exec, JSValue::decode(encodedValue)); return JSValue::encode(jsNumber(array->length())); } EncodedJSValue DFG_OPERATION operationArrayPop(ExecState* exec, JSArray* array) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return JSValue::encode(array->pop(exec)); } void DFG_OPERATION operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + PutPropertySlot slot(true); base->methodTable()->put(base, exec, *propertyName, JSValue::decode(encodedValue), slot); } void DFG_OPERATION operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + PutPropertySlot slot(false); base->methodTable()->put(base, exec, *propertyName, JSValue::decode(encodedValue), slot); } void DFG_OPERATION operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + PutPropertySlot slot(true); - JSValue(base).putDirect(exec, *propertyName, JSValue::decode(encodedValue), slot); + ASSERT(base->isObject()); + asObject(base)->putDirect(exec->globalData(), *propertyName, JSValue::decode(encodedValue), slot); } void DFG_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + PutPropertySlot slot(false); - JSValue(base).putDirect(exec, *propertyName, JSValue::decode(encodedValue), slot); + ASSERT(base->isObject()); + asObject(base)->putDirect(exec->globalData(), *propertyName, JSValue::decode(encodedValue), slot); } V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdStrictOptimize); void DFG_OPERATION operationPutByIdStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue value = JSValue::decode(encodedValue); JSValue baseValue(base); PutPropertySlot slot(true); @@ -459,6 +557,9 @@ void DFG_OPERATION operationPutByIdStrictOptimizeWithReturnAddress(ExecState* ex V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdNonStrictOptimize); void DFG_OPERATION operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue value = JSValue::decode(encodedValue); JSValue baseValue(base); PutPropertySlot slot(false); @@ -475,15 +576,18 @@ void DFG_OPERATION operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState* V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectStrictOptimize); void DFG_OPERATION operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue value = JSValue::decode(encodedValue); - JSValue baseValue(base); PutPropertySlot slot(true); - baseValue.putDirect(exec, *propertyName, value, slot); + ASSERT(base->isObject()); + asObject(base)->putDirect(exec->globalData(), *propertyName, value, slot); StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); if (stubInfo.seen) - dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, Direct); + dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct); else stubInfo.seen = true; } @@ -491,46 +595,67 @@ void DFG_OPERATION operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecSta V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectNonStrictOptimize); void DFG_OPERATION operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue value = JSValue::decode(encodedValue); - JSValue baseValue(base); PutPropertySlot slot(false); - baseValue.putDirect(exec, *propertyName, value, slot); + ASSERT(base->isObject()); + asObject(base)->putDirect(exec->globalData(), *propertyName, value, slot); StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); if (stubInfo.seen) - dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, Direct); + dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct); else stubInfo.seen = true; } size_t DFG_OPERATION operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return jsLess<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); } size_t DFG_OPERATION operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return jsLessEq<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); } size_t DFG_OPERATION operationCompareGreater(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return jsLess<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1)); } size_t DFG_OPERATION operationCompareGreaterEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return jsLessEq<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1)); } size_t DFG_OPERATION operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return JSValue::equalSlowCaseInline(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); } size_t DFG_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue op1 = JSValue::decode(encodedOp1); JSValue op2 = JSValue::decode(encodedOp2); @@ -542,6 +667,9 @@ size_t DFG_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValu size_t DFG_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return JSValue::strictEqual(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); } @@ -551,6 +679,7 @@ EncodedJSValue DFG_OPERATION getHostCallReturnValueWithExecState(ExecState*); #if CPU(X86_64) asm ( ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" +HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" "mov -40(%r13), %r13\n" "mov %r13, %rdi\n" @@ -559,6 +688,7 @@ SYMBOL_STRING(getHostCallReturnValue) ":" "\n" #elif CPU(X86) asm ( ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" +HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" "mov -40(%edi), %edi\n" "mov %edi, 4(%esp)\n" @@ -581,6 +711,9 @@ SYMBOL_STRING(getHostCallReturnValue) ":" "\n" EncodedJSValue DFG_OPERATION getHostCallReturnValueWithExecState(ExecState* exec) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return JSValue::encode(exec->globalData().hostCallReturnValue); } @@ -635,6 +768,8 @@ inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress, Code { ExecState* exec = execCallee->callerFrame(); JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); if (!calleeAsFunctionCell) @@ -684,6 +819,9 @@ void* DFG_OPERATION operationLinkConstructWithReturnAddress(ExecState* execCalle inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); if (UNLIKELY(!calleeAsFunctionCell)) @@ -704,7 +842,7 @@ inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) } void* DFG_OPERATION operationVirtualCall(ExecState* execCallee) -{ +{ return virtualFor(execCallee, CodeForCall); } @@ -715,6 +853,9 @@ void* DFG_OPERATION operationVirtualConstruct(ExecState* execCallee) EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* propertyName) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + ScopeChainNode* scopeChain = exec->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); @@ -732,11 +873,17 @@ EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* prope EncodedJSValue DFG_OPERATION operationResolveBase(ExecState* exec, Identifier* propertyName) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return JSValue::encode(resolveBase(exec, *propertyName, exec->scopeChain(), false)); } EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState* exec, Identifier* propertyName) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue base = resolveBase(exec, *propertyName, exec->scopeChain(), true); if (!base) throwError(exec, createErrorForInvalidGlobalAssignment(exec, propertyName->ustring())); @@ -745,6 +892,9 @@ EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState* exec, Iden EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState* exec, GlobalResolveInfo* resolveInfo, Identifier* propertyName) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); PropertySlot slot(globalObject); @@ -764,16 +914,25 @@ EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState* exec, GlobalResol EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return JSValue::encode(JSValue::decode(value).toPrimitive(exec)); } EncodedJSValue DFG_OPERATION operationStrCat(ExecState* exec, void* start, size_t size) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return JSValue::encode(jsString(exec, static_cast<Register*>(start), size)); } EncodedJSValue DFG_OPERATION operationNewArray(ExecState* exec, void* start, size_t size) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return JSValue::encode(constructArray(exec, static_cast<JSValue*>(start), size)); } @@ -795,6 +954,9 @@ EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState* exec, uint32_t callIndex) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + JSValue exceptionValue = exec->exception(); ASSERT(exceptionValue); @@ -806,29 +968,60 @@ DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState* exec, uint32_t return dfgHandlerEncoded(exec, catchRoutine); } +DFGHandlerEncoded DFG_OPERATION lookupExceptionHandlerInStub(ExecState* exec, StructureStubInfo* stubInfo) +{ + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + + JSValue exceptionValue = exec->exception(); + ASSERT(exceptionValue); + + CodeOrigin codeOrigin = stubInfo->codeOrigin; + while (codeOrigin.inlineCallFrame) + codeOrigin = codeOrigin.inlineCallFrame->caller; + + HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, codeOrigin.bytecodeIndex); + + void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught; + ASSERT(catchRoutine); + return dfgHandlerEncoded(exec, catchRoutine); +} + double DFG_OPERATION dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return JSValue::decode(value).toNumber(exec); } size_t DFG_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + // toInt32/toUInt32 return the same value; we want the value zero extended to fill the register. return JSValue::decode(value).toUInt32(exec); } size_t DFG_OPERATION dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + return JSValue::decode(encodedOp).toBoolean(exec); } #if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE) -void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState*, void* debugInfoRaw) +void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* debugInfoRaw) { + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw); CodeBlock* codeBlock = debugInfo->codeBlock; CodeBlock* alternative = codeBlock->alternative(); - printf("Speculation failure in %p at @%u with executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, success/fail %u/%u\n", codeBlock, debugInfo->nodeIndex, alternative ? alternative->executeCounter() : 0, alternative ? alternative->reoptimizationRetryCounter() : 0, alternative ? alternative->optimizationDelayCounter() : 0, codeBlock->speculativeSuccessCounter(), codeBlock->speculativeFailCounter()); + printf("Speculation failure in %p at @%u with executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, success/fail %u/%u\n", codeBlock, debugInfo->nodeIndex, alternative ? alternative->jitExecuteCounter() : 0, alternative ? alternative->reoptimizationRetryCounter() : 0, alternative ? alternative->optimizationDelayCounter() : 0, codeBlock->speculativeSuccessCounter(), codeBlock->speculativeFailCounter()); } #endif diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h index b4121dc21..5de9d3af3 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.h +++ b/Source/JavaScriptCore/dfg/DFGOperations.h @@ -104,7 +104,8 @@ EncodedJSValue DFG_OPERATION operationGetById(ExecState*, EncodedJSValue, Identi EncodedJSValue DFG_OPERATION operationGetByIdBuildList(ExecState*, EncodedJSValue, Identifier*); EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildList(ExecState*, EncodedJSValue, Identifier*); EncodedJSValue DFG_OPERATION operationGetByIdOptimize(ExecState*, EncodedJSValue, Identifier*); -EncodedJSValue DFG_OPERATION operationGetMethodOptimize(ExecState*, EncodedJSValue, Identifier*); +EncodedJSValue DFG_OPERATION operationCallCustomGetter(ExecState*, JSCell*, PropertySlot::GetValueFunc, Identifier*); +EncodedJSValue DFG_OPERATION operationCallGetter(ExecState*, JSCell*, JSCell*); EncodedJSValue DFG_OPERATION operationResolve(ExecState*, Identifier*); EncodedJSValue DFG_OPERATION operationResolveBase(ExecState*, Identifier*); EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState*, Identifier*); @@ -181,6 +182,7 @@ inline DFGHandlerEncoded dfgHandlerEncoded(ExecState* exec, void* handler) } #endif DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState*, uint32_t); +DFGHandlerEncoded DFG_OPERATION lookupExceptionHandlerInStub(ExecState*, StructureStubInfo*); // These operations implement the implicitly called ToInt32, ToNumber, and ToBoolean conversions from ES5. double DFG_OPERATION dfgConvertJSValueToNumber(ExecState*, EncodedJSValue); diff --git a/Source/JavaScriptCore/dfg/DFGPropagator.cpp b/Source/JavaScriptCore/dfg/DFGPropagator.cpp index 631e82830..acfd2d364 100644 --- a/Source/JavaScriptCore/dfg/DFGPropagator.cpp +++ b/Source/JavaScriptCore/dfg/DFGPropagator.cpp @@ -382,7 +382,7 @@ private: if (left && right) { if (isNumberPrediction(left) && isNumberPrediction(right)) { - if (isInt32Prediction(mergePredictions(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) + if (m_graph.addShouldSpeculateInteger(node, m_codeBlock)) changed |= mergePrediction(PredictInt32); else changed |= mergePrediction(PredictDouble); @@ -396,7 +396,19 @@ private: } case ArithAdd: - case ArithSub: + case ArithSub: { + PredictedType left = m_graph[node.child1()].prediction(); + PredictedType right = m_graph[node.child2()].prediction(); + + if (left && right) { + if (m_graph.addShouldSpeculateInteger(node, m_codeBlock)) + changed |= mergePrediction(PredictInt32); + else + changed |= mergePrediction(PredictDouble); + } + break; + } + case ArithMul: case ArithMin: case ArithMax: @@ -454,16 +466,22 @@ private: bool isInt16Array = m_graph[node.child1()].shouldSpeculateInt16Array(); bool isInt32Array = m_graph[node.child1()].shouldSpeculateInt32Array(); bool isUint8Array = m_graph[node.child1()].shouldSpeculateUint8Array(); + bool isUint8ClampedArray = m_graph[node.child1()].shouldSpeculateUint8ClampedArray(); bool isUint16Array = m_graph[node.child1()].shouldSpeculateUint16Array(); bool isUint32Array = m_graph[node.child1()].shouldSpeculateUint32Array(); bool isFloat32Array = m_graph[node.child1()].shouldSpeculateFloat32Array(); bool isFloat64Array = m_graph[node.child1()].shouldSpeculateFloat64Array(); - if (isArray || isString || isByteArray || isInt8Array || isInt16Array || isInt32Array || isUint8Array || isUint16Array || isUint32Array || isFloat32Array || isFloat64Array) + if (isArray || isString || isByteArray || isInt8Array || isInt16Array || isInt32Array || isUint8Array || isUint8ClampedArray || isUint16Array || isUint32Array || isFloat32Array || isFloat64Array) changed |= mergePrediction(PredictInt32); } break; } + case GetByIdFlush: + if (node.getHeapPrediction()) + changed |= mergePrediction(node.getHeapPrediction()); + break; + case GetByVal: { if (m_graph[node.child1()].shouldSpeculateUint32Array() || m_graph[node.child1()].shouldSpeculateFloat32Array() || m_graph[node.child1()].shouldSpeculateFloat64Array()) changed |= mergePrediction(PredictDouble); @@ -586,6 +604,7 @@ private: case GetInt16ArrayLength: case GetInt32ArrayLength: case GetUint8ArrayLength: + case GetUint8ClampedArrayLength: case GetUint16ArrayLength: case GetUint32ArrayLength: case GetFloat32ArrayLength: @@ -705,7 +724,23 @@ private: switch (node.op) { case ValueAdd: case ArithAdd: - case ArithSub: + case ArithSub: { + PredictedType left = m_graph[node.child1()].prediction(); + PredictedType right = m_graph[node.child2()].prediction(); + + VariableAccessData::Ballot ballot; + + if (isNumberPrediction(left) && isNumberPrediction(right) + && !m_graph.addShouldSpeculateInteger(node, m_codeBlock)) + ballot = VariableAccessData::VoteDouble; + else + ballot = VariableAccessData::VoteValue; + + vote(node.child1(), ballot); + vote(node.child2(), ballot); + break; + } + case ArithMul: case ArithMin: case ArithMax: @@ -822,27 +857,21 @@ private: #endif switch (op) { - case ValueAdd: { - if (!nodeCanSpeculateInteger(node.arithNodeFlags())) { - toDouble(node.child1()); - toDouble(node.child2()); - break; - } - + case ValueAdd: + case ArithAdd: + case ArithSub: { PredictedType left = m_graph[node.child1()].prediction(); PredictedType right = m_graph[node.child2()].prediction(); if (left && right && isNumberPrediction(left) && isNumberPrediction(right) - && ((left & PredictDouble) || (right & PredictDouble))) { + && !m_graph.addShouldSpeculateInteger(node, m_codeBlock)) { toDouble(node.child1()); toDouble(node.child2()); } break; } - case ArithAdd: - case ArithSub: case ArithMul: case ArithMin: case ArithMax: @@ -894,11 +923,12 @@ private: bool isInt16Array = m_graph[node.child1()].shouldSpeculateInt16Array(); bool isInt32Array = m_graph[node.child1()].shouldSpeculateInt32Array(); bool isUint8Array = m_graph[node.child1()].shouldSpeculateUint8Array(); + bool isUint8ClampedArray = m_graph[node.child1()].shouldSpeculateUint8ClampedArray(); bool isUint16Array = m_graph[node.child1()].shouldSpeculateUint16Array(); bool isUint32Array = m_graph[node.child1()].shouldSpeculateUint32Array(); bool isFloat32Array = m_graph[node.child1()].shouldSpeculateFloat32Array(); bool isFloat64Array = m_graph[node.child1()].shouldSpeculateFloat64Array(); - if (!isArray && !isString && !isByteArray && !isInt8Array && !isInt16Array && !isInt32Array && !isUint8Array && !isUint16Array && !isUint32Array && !isFloat32Array && !isFloat64Array) + if (!isArray && !isString && !isByteArray && !isInt8Array && !isInt16Array && !isInt32Array && !isUint8Array && !isUint8ClampedArray && !isUint16Array && !isUint32Array && !isFloat32Array && !isFloat64Array) break; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) @@ -918,6 +948,8 @@ private: node.op = GetInt32ArrayLength; else if (isUint8Array) node.op = GetUint8ArrayLength; + else if (isUint8ClampedArray) + node.op = GetUint8ClampedArrayLength; else if (isUint16Array) node.op = GetUint16ArrayLength; else if (isUint32Array) @@ -1517,6 +1549,7 @@ private: case GetInt16ArrayLength: case GetInt32ArrayLength: case GetUint8ArrayLength: + case GetUint8ClampedArrayLength: case GetUint16ArrayLength: case GetUint32ArrayLength: case GetFloat32ArrayLength: diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp index ae4a44ffe..f2928c290 100644 --- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp +++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp @@ -28,6 +28,7 @@ #if ENABLE(DFG_JIT) +#include "DFGCCallHelpers.h" #include "DFGSpeculativeJIT.h" #include "LinkBuffer.h" #include "Operations.h" @@ -149,7 +150,7 @@ static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stu emitRestoreScratch(stubJit, needToRestoreScratch, scratchGPR, success, fail, failureCases); - LinkBuffer patchBuffer(*globalData, &stubJit); + LinkBuffer patchBuffer(*globalData, &stubJit, exec->codeBlock()); linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, successLabel, slowCaseLabel); @@ -200,7 +201,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier emitRestoreScratch(stubJit, needToRestoreScratch, scratchGPR, success, fail, failureCases); - LinkBuffer patchBuffer(*globalData, &stubJit); + LinkBuffer patchBuffer(*globalData, &stubJit, codeBlock); linkRestoreScratch(patchBuffer, needToRestoreScratch, stubInfo, success, fail, failureCases); @@ -227,8 +228,10 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier // Optimize self access. if (slot.slotBase() == baseValue) { - if ((slot.cachedPropertyType() != PropertySlot::Value) || ((slot.cachedOffset() * sizeof(JSValue)) > (unsigned)MacroAssembler::MaximumCompactPtrAlignedAddressOffset)) - return false; + if ((slot.cachedPropertyType() != PropertySlot::Value) || ((slot.cachedOffset() * sizeof(JSValue)) > (unsigned)MacroAssembler::MaximumCompactPtrAlignedAddressOffset)) { + dfgRepatchCall(codeBlock, stubInfo.callReturnLocation, operationGetByIdBuildList); + return true; + } dfgRepatchByIdSelfAccess(codeBlock, stubInfo, structure, slot.cachedOffset(), operationGetByIdBuildList, true); stubInfo.initGetByIdSelf(*globalData, codeBlock->ownerExecutable(), structure); @@ -268,16 +271,22 @@ void dfgRepatchGetByID(ExecState* exec, JSValue baseValue, const Identifier& pro dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationGetById); } -static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identifier&, const PropertySlot& slot, StructureStubInfo& stubInfo) +static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identifier& ident, const PropertySlot& slot, StructureStubInfo& stubInfo) { if (!baseValue.isCell() || !slot.isCacheable() || baseValue.asCell()->structure()->isUncacheableDictionary() - || slot.slotBase() != baseValue - || slot.cachedPropertyType() != PropertySlot::Value - || (slot.cachedOffset() * sizeof(JSValue)) > (unsigned)MacroAssembler::MaximumCompactPtrAlignedAddressOffset) + || slot.slotBase() != baseValue) return false; + if (!stubInfo.registersFlushed) { + // We cannot do as much inline caching if the registers were not flushed prior to this GetById. In particular, + // non-Value cached properties require planting calls, which requires registers to have been flushed. Thus, + // if registers were not flushed, don't do non-Value caching. + if (slot.cachedPropertyType() != PropertySlot::Value) + return false; + } + CodeBlock* codeBlock = exec->codeBlock(); JSCell* baseCell = baseValue.asCell(); Structure* structure = baseCell->structure(); @@ -286,12 +295,18 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi ASSERT(slot.slotBase().isObject()); PolymorphicAccessStructureList* polymorphicStructureList; - int listIndex = 1; + int listIndex; - if (stubInfo.accessType == access_get_by_id_self) { + if (stubInfo.accessType == access_unset) { + ASSERT(!stubInfo.stubRoutine); + polymorphicStructureList = new PolymorphicAccessStructureList(); + stubInfo.initGetByIdSelfList(polymorphicStructureList, 0); + listIndex = 0; + } else if (stubInfo.accessType == access_get_by_id_self) { ASSERT(!stubInfo.stubRoutine); polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), MacroAssemblerCodeRef::createSelfManagedCodeRef(stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase)), stubInfo.u.getByIdSelf.baseObjectStructure.get(), true); stubInfo.initGetByIdSelfList(polymorphicStructureList, 1); + listIndex = 1; } else { polymorphicStructureList = stubInfo.u.getByIdSelfList.structureList; listIndex = stubInfo.u.getByIdSelfList.listSize; @@ -305,32 +320,93 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi GPRReg resultTagGPR = static_cast<GPRReg>(stubInfo.valueTagGPR); #endif GPRReg resultGPR = static_cast<GPRReg>(stubInfo.valueGPR); + GPRReg scratchGPR = static_cast<GPRReg>(stubInfo.scratchGPR); - MacroAssembler stubJit; + CCallHelpers stubJit(globalData, codeBlock); MacroAssembler::Jump wrongStruct = stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(structure)); - - stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR); + + // The strategy we use for stubs is as follows: + // 1) Call DFG helper that calls the getter. + // 2) Check if there was an exception, and if there was, call yet another + // helper. + + bool isDirect = false; + MacroAssembler::Call operationCall; + MacroAssembler::Call handlerCall; + FunctionPtr operationFunction; + MacroAssembler::Jump success; + + if (slot.cachedPropertyType() == PropertySlot::Getter + || slot.cachedPropertyType() == PropertySlot::Custom) { + if (slot.cachedPropertyType() == PropertySlot::Getter) { + ASSERT(baseGPR != scratchGPR); + stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR); #if USE(JSVALUE64) - stubJit.loadPtr(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue)), resultGPR); + stubJit.loadPtr(MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue)), scratchGPR); #elif USE(JSVALUE32_64) - stubJit.load32(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR); - stubJit.load32(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR); + stubJit.load32(MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), scratchGPR); #endif + stubJit.setupArgumentsWithExecState(baseGPR, scratchGPR); + operationFunction = operationCallGetter; + } else { + stubJit.setupArgumentsWithExecState( + baseGPR, + MacroAssembler::TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress()), + MacroAssembler::TrustedImmPtr(const_cast<Identifier*>(&ident))); + operationFunction = operationCallCustomGetter; + } + + // Need to make sure that whenever this call is made in the future, we remember the + // place that we made it from. It just so happens to be the place that we are at + // right now! + stubJit.store32( + MacroAssembler::TrustedImm32(exec->codeOriginIndexForDFGWithInlining()), + CCallHelpers::tagFor(static_cast<VirtualRegister>(RegisterFile::ArgumentCount))); + + operationCall = stubJit.call(); +#if USE(JSVALUE64) + stubJit.move(GPRInfo::returnValueGPR, resultGPR); +#else + stubJit.setupResults(resultGPR, resultTagGPR); +#endif + success = stubJit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck); + + stubJit.setupArgumentsWithExecState( + MacroAssembler::TrustedImmPtr(&stubInfo)); + handlerCall = stubJit.call(); + stubJit.jump(GPRInfo::returnValueGPR2); + } else { + stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR); +#if USE(JSVALUE64) + stubJit.loadPtr(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue)), resultGPR); +#elif USE(JSVALUE32_64) + stubJit.load32(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR); + stubJit.load32(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR); +#endif + success = stubJit.jump(); + isDirect = true; + } - MacroAssembler::Jump success = stubJit.jump(); - - LinkBuffer patchBuffer(*globalData, &stubJit); + LinkBuffer patchBuffer(*globalData, &stubJit, codeBlock); - CodeLocationLabel lastProtoBegin = CodeLocationLabel(polymorphicStructureList->list[listIndex - 1].stubRoutine.code()); + CodeLocationLabel lastProtoBegin; + if (listIndex) + lastProtoBegin = CodeLocationLabel(polymorphicStructureList->list[listIndex - 1].stubRoutine.code()); + else + lastProtoBegin = stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase); ASSERT(!!lastProtoBegin); patchBuffer.link(wrongStruct, lastProtoBegin); patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone)); + if (!isDirect) { + patchBuffer.link(operationCall, operationFunction); + patchBuffer.link(handlerCall, lookupExceptionHandlerInStub); + } MacroAssemblerCodeRef stubRoutine = patchBuffer.finalizeCode(); - polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, true); + polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, isDirect); CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck); RepatchBuffer repatchBuffer(codeBlock); @@ -538,7 +614,7 @@ static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier } else success = stubJit.jump(); - LinkBuffer patchBuffer(*globalData, &stubJit); + LinkBuffer patchBuffer(*globalData, &stubJit, codeBlock); patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone)); if (needToRestoreScratch) patchBuffer.link(failure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase)); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index feb705ab8..e647fb87a 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -1112,6 +1112,11 @@ void SpeculativeJIT::checkArgumentTypes() m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ArrayDescriptor().m_classInfo))); + } else if (isUint8ClampedArrayPrediction(predictedType)) { + GPRTemporary temp(this); + m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ClampedArrayDescriptor().m_classInfo))); } else if (isUint16ArrayPrediction(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); @@ -1174,6 +1179,12 @@ void SpeculativeJIT::checkArgumentTypes() speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ArrayDescriptor().m_classInfo))); + } else if (isUint8ClampedArrayPrediction(predictedType)) { + GPRTemporary temp(this); + m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); + m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ClampedArrayDescriptor().m_classInfo))); } else if (isUint16ArrayPrediction(predictedType)) { GPRTemporary temp(this); m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); @@ -1529,6 +1540,28 @@ void SpeculativeJIT::compileUInt32ToNumber(Node& node) integerResult(result.gpr(), m_compileIndex, op1.format()); } +static double clampDoubleToByte(double d) +{ + d += 0.5; + if (!(d > 0)) + d = 0; + else if (d > 255) + d = 255; + return d; +} + +static void compileClampIntegerToByte(JITCompiler& jit, GPRReg result) +{ + MacroAssembler::Jump inBounds = jit.branch32(MacroAssembler::BelowOrEqual, result, JITCompiler::TrustedImm32(0xff)); + MacroAssembler::Jump tooBig = jit.branch32(MacroAssembler::GreaterThan, result, JITCompiler::TrustedImm32(0xff)); + jit.xorPtr(result, result); + MacroAssembler::Jump clamped = jit.jump(); + tooBig.link(&jit); + jit.move(JITCompiler::TrustedImm32(255), result); + clamped.link(&jit); + inBounds.link(&jit); +} + static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg source, FPRReg scratch) { // Unordered compare so we pick up NaN @@ -1576,15 +1609,10 @@ void SpeculativeJIT::compilePutByValForByteArray(GPRReg base, GPRReg property, N noResult(m_compileIndex); return; } - double d = jsValue.asNumber(); - d += 0.5; - if (!(d > 0)) - d = 0; - else if (d > 255) - d = 255; + int clampedValue = clampDoubleToByte(jsValue.asNumber()); GPRTemporary scratch(this); GPRReg scratchReg = scratch.gpr(); - m_jit.move(Imm32((int)d), scratchReg); + m_jit.move(Imm32(clampedValue), scratchReg); value.adopt(scratch); valueGPR = scratchReg; } else if (!at(valueIndex).shouldNotSpeculateInteger()) { @@ -1592,14 +1620,7 @@ void SpeculativeJIT::compilePutByValForByteArray(GPRReg base, GPRReg property, N GPRTemporary scratch(this); GPRReg scratchReg = scratch.gpr(); m_jit.move(valueOp.gpr(), scratchReg); - MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::BelowOrEqual, scratchReg, TrustedImm32(0xff)); - MacroAssembler::Jump tooBig = m_jit.branch32(MacroAssembler::GreaterThan, scratchReg, TrustedImm32(0xff)); - m_jit.xorPtr(scratchReg, scratchReg); - MacroAssembler::Jump clamped = m_jit.jump(); - tooBig.link(&m_jit); - m_jit.move(TrustedImm32(255), scratchReg); - clamped.link(&m_jit); - inBounds.link(&m_jit); + compileClampIntegerToByte(m_jit, scratchReg); value.adopt(scratch); valueGPR = scratchReg; } else { @@ -1722,7 +1743,7 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& } } -void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements, TypedArraySignedness signedness) +void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements, TypedArraySignedness signedness, TypedArrayRounding rounding) { NodeIndex baseIndex = node.child1(); NodeIndex valueIndex = node.child3(); @@ -1740,9 +1761,13 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& return; } double d = jsValue.asNumber(); + if (rounding == ClampRounding) { + ASSERT(elementSize == 1); + d = clampDoubleToByte(d); + } GPRTemporary scratch(this); GPRReg scratchReg = scratch.gpr(); - m_jit.move(Imm32((int)d), scratchReg); + m_jit.move(Imm32(static_cast<int>(d)), scratchReg); value.adopt(scratch); valueGPR = scratchReg; } else if (!at(valueIndex).shouldNotSpeculateInteger()) { @@ -1750,8 +1775,22 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& GPRTemporary scratch(this); GPRReg scratchReg = scratch.gpr(); m_jit.move(valueOp.gpr(), scratchReg); + if (rounding == ClampRounding) { + ASSERT(elementSize == 1); + compileClampIntegerToByte(m_jit, scratchReg); + } value.adopt(scratch); valueGPR = scratchReg; + } else if (rounding == ClampRounding) { + ASSERT(elementSize == 1); + SpeculateDoubleOperand valueOp(this, valueIndex); + GPRTemporary result(this); + FPRTemporary floatScratch(this); + FPRReg fpr = valueOp.fpr(); + GPRReg gpr = result.gpr(); + compileClampDoubleToByte(m_jit, gpr, fpr, floatScratch.fpr()); + value.adopt(result); + valueGPR = gpr; } else { SpeculateDoubleOperand valueOp(this, valueIndex); GPRTemporary result(this); @@ -1761,17 +1800,17 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& m_jit.xorPtr(gpr, gpr); MacroAssembler::Jump fixed = m_jit.jump(); notNaN.link(&m_jit); - + MacroAssembler::Jump done; if (signedness == SignedTypedArray) done = m_jit.branchTruncateDoubleToInt32(fpr, gpr, MacroAssembler::BranchIfTruncateSuccessful); else done = m_jit.branchTruncateDoubleToUint32(fpr, gpr, MacroAssembler::BranchIfTruncateSuccessful); - + silentSpillAllRegisters(gpr); callOperation(toInt32, gpr, fpr); silentFillAllRegisters(gpr); - + done.link(&m_jit); fixed.link(&m_jit); value.adopt(result); @@ -2157,6 +2196,144 @@ void SpeculativeJIT::compileSoftModulo(Node& node) #endif } +void SpeculativeJIT::compileAdd(Node& node) +{ + if (m_jit.graph().addShouldSpeculateInteger(node, m_jit.codeBlock())) { + if (isNumberConstant(node.child1())) { + int32_t imm1 = valueOfNumberConstantAsInt32(node.child1()); + SpeculateIntegerOperand op2(this, node.child2()); + GPRTemporary result(this); + + if (nodeCanTruncateInteger(node.arithNodeFlags())) { + m_jit.move(op2.gpr(), result.gpr()); + m_jit.add32(Imm32(imm1), result.gpr()); + } else + speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr())); + + integerResult(result.gpr(), m_compileIndex); + return; + } + + if (isNumberConstant(node.child2())) { + SpeculateIntegerOperand op1(this, node.child1()); + int32_t imm2 = valueOfNumberConstantAsInt32(node.child2()); + GPRTemporary result(this); + + if (nodeCanTruncateInteger(node.arithNodeFlags())) { + m_jit.move(op1.gpr(), result.gpr()); + m_jit.add32(Imm32(imm2), result.gpr()); + } else + speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr())); + + integerResult(result.gpr(), m_compileIndex); + return; + } + + SpeculateIntegerOperand op1(this, node.child1()); + SpeculateIntegerOperand op2(this, node.child2()); + GPRTemporary result(this, op1, op2); + + GPRReg gpr1 = op1.gpr(); + GPRReg gpr2 = op2.gpr(); + GPRReg gprResult = result.gpr(); + + if (nodeCanTruncateInteger(node.arithNodeFlags())) { + if (gpr1 == gprResult) + m_jit.add32(gpr2, gprResult); + else { + m_jit.move(gpr2, gprResult); + m_jit.add32(gpr1, gprResult); + } + } else { + MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult); + + if (gpr1 == gprResult) + speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2)); + else if (gpr2 == gprResult) + speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1)); + else + speculationCheck(Overflow, JSValueRegs(), NoNode, check); + } + + integerResult(gprResult, m_compileIndex); + return; + } + + if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) { + SpeculateDoubleOperand op1(this, node.child1()); + SpeculateDoubleOperand op2(this, node.child2()); + FPRTemporary result(this, op1, op2); + + FPRReg reg1 = op1.fpr(); + FPRReg reg2 = op2.fpr(); + m_jit.addDouble(reg1, reg2, result.fpr()); + + doubleResult(result.fpr(), m_compileIndex); + return; + } + + ASSERT(node.op == ValueAdd); + compileValueAdd(node); +} + +void SpeculativeJIT::compileArithSub(Node& node) +{ + if (m_jit.graph().addShouldSpeculateInteger(node, m_jit.codeBlock())) { + if (isNumberConstant(node.child2())) { + SpeculateIntegerOperand op1(this, node.child1()); + int32_t imm2 = valueOfNumberConstantAsInt32(node.child2()); + GPRTemporary result(this); + + if (nodeCanTruncateInteger(node.arithNodeFlags())) { + m_jit.move(op1.gpr(), result.gpr()); + m_jit.sub32(Imm32(imm2), result.gpr()); + } else + speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr())); + + integerResult(result.gpr(), m_compileIndex); + return; + } + + if (isNumberConstant(node.child1())) { + int32_t imm1 = valueOfNumberConstantAsInt32(node.child1()); + SpeculateIntegerOperand op2(this, node.child2()); + GPRTemporary result(this); + + m_jit.move(Imm32(imm1), result.gpr()); + if (nodeCanTruncateInteger(node.arithNodeFlags())) + m_jit.sub32(op2.gpr(), result.gpr()); + else + speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op2.gpr(), result.gpr())); + + integerResult(result.gpr(), m_compileIndex); + return; + } + + SpeculateIntegerOperand op1(this, node.child1()); + SpeculateIntegerOperand op2(this, node.child2()); + GPRTemporary result(this); + + if (nodeCanTruncateInteger(node.arithNodeFlags())) { + m_jit.move(op1.gpr(), result.gpr()); + m_jit.sub32(op2.gpr(), result.gpr()); + } else + speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr())); + + integerResult(result.gpr(), m_compileIndex); + return; + } + + SpeculateDoubleOperand op1(this, node.child1()); + SpeculateDoubleOperand op2(this, node.child2()); + FPRTemporary result(this, op1); + + FPRReg reg1 = op1.fpr(); + FPRReg reg2 = op2.fpr(); + m_jit.subDouble(reg1, reg2, result.fpr()); + + doubleResult(result.fpr(), m_compileIndex); +} + void SpeculativeJIT::compileArithMul(Node& node) { if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { @@ -2451,6 +2628,11 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node) if (!isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); + } else if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { + const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ClampedArrayDescriptor(); + if (!isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type)) + speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); + m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateUint16Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint16ArrayDescriptor(); if (!isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type)) diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 3b709400d..0098da3a1 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -325,18 +325,21 @@ public: void writeBarrier(GPRReg ownerGPR, JSCell* value, WriteBarrierUseKind, GPRReg scratchGPR1 = InvalidGPRReg, GPRReg scratchGPR2 = InvalidGPRReg); void writeBarrier(JSCell* owner, GPRReg valueGPR, NodeIndex valueIndex, WriteBarrierUseKind, GPRReg scratchGPR1 = InvalidGPRReg); - static GPRReg selectScratchGPR(GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg) + static GPRReg selectScratchGPR(GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg, GPRReg preserve4 = InvalidGPRReg) { - if (preserve1 != GPRInfo::regT0 && preserve2 != GPRInfo::regT0 && preserve3 != GPRInfo::regT0) + if (preserve1 != GPRInfo::regT0 && preserve2 != GPRInfo::regT0 && preserve3 != GPRInfo::regT0 && preserve4 != GPRInfo::regT0) return GPRInfo::regT0; - if (preserve1 != GPRInfo::regT1 && preserve2 != GPRInfo::regT1 && preserve3 != GPRInfo::regT1) + if (preserve1 != GPRInfo::regT1 && preserve2 != GPRInfo::regT1 && preserve3 != GPRInfo::regT1 && preserve4 != GPRInfo::regT1) return GPRInfo::regT1; - if (preserve1 != GPRInfo::regT2 && preserve2 != GPRInfo::regT2 && preserve3 != GPRInfo::regT2) + if (preserve1 != GPRInfo::regT2 && preserve2 != GPRInfo::regT2 && preserve3 != GPRInfo::regT2 && preserve4 != GPRInfo::regT2) return GPRInfo::regT2; - return GPRInfo::regT3; + if (preserve1 != GPRInfo::regT3 && preserve2 != GPRInfo::regT3 && preserve3 != GPRInfo::regT3 && preserve4 != GPRInfo::regT3) + return GPRInfo::regT3; + + return GPRInfo::regT4; } // Called by the speculative operand types, below, to fill operand to @@ -727,6 +730,12 @@ private: bool isFunctionConstant(NodeIndex nodeIndex) { return m_jit.isFunctionConstant(nodeIndex); } int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return m_jit.valueOfInt32Constant(nodeIndex); } double valueOfNumberConstant(NodeIndex nodeIndex) { return m_jit.valueOfNumberConstant(nodeIndex); } + int32_t valueOfNumberConstantAsInt32(NodeIndex nodeIndex) + { + if (isInt32Constant(nodeIndex)) + return valueOfInt32Constant(nodeIndex); + return JSC::toInt32(valueOfNumberConstant(nodeIndex)); + } #if USE(JSVALUE32_64) void* addressOfDoubleConstant(NodeIndex nodeIndex) { return m_jit.addressOfDoubleConstant(nodeIndex); } #endif @@ -872,12 +881,13 @@ private: void nonSpeculativeValueToInt32(Node&); void nonSpeculativeUInt32ToNumber(Node&); + enum SpillRegistersMode { NeedToSpill, DontSpill }; #if USE(JSVALUE64) - JITCompiler::Call cachedGetById(GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump()); - void cachedPutById(GPRReg base, GPRReg value, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump()); + JITCompiler::Call cachedGetById(CodeOrigin, GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill); + void cachedPutById(CodeOrigin, GPRReg base, GPRReg value, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump()); #elif USE(JSVALUE32_64) - JITCompiler::Call cachedGetById(GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump()); - void cachedPutById(GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump()); + JITCompiler::Call cachedGetById(CodeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill); + void cachedPutById(CodeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump()); #endif void nonSpeculativeNonPeepholeCompareNull(NodeIndex operand, bool invert = false); @@ -1060,457 +1070,6 @@ private: m_generationInfo[node.virtualRegister()].initConstant(nodeIndex, node.refCount()); } - // These methods used to sort arguments into the correct registers. - // On X86 we use cdecl calling conventions, which pass all arguments on the - // stack. On other architectures we may need to sort values into the - // correct registers. -#if !NUMBER_OF_ARGUMENT_REGISTERS - unsigned m_callArgumentOffset; - void resetCallArguments() { m_callArgumentOffset = 0; } - - // These methods are using internally to implement the callOperation methods. - void addCallArgument(GPRReg value) - { - m_jit.poke(value, m_callArgumentOffset++); - } - void addCallArgument(TrustedImm32 imm) - { - m_jit.poke(imm, m_callArgumentOffset++); - } - void addCallArgument(TrustedImmPtr pointer) - { - m_jit.poke(pointer, m_callArgumentOffset++); - } - void addCallArgument(FPRReg value) - { - m_jit.storeDouble(value, JITCompiler::Address(JITCompiler::stackPointerRegister, m_callArgumentOffset * sizeof(void*))); - m_callArgumentOffset += sizeof(double) / sizeof(void*); - } - - ALWAYS_INLINE void setupArguments(FPRReg arg1) - { - resetCallArguments(); - addCallArgument(arg1); - } - - ALWAYS_INLINE void setupArguments(FPRReg arg1, FPRReg arg2) - { - resetCallArguments(); - addCallArgument(arg1); - addCallArgument(arg2); - } - - ALWAYS_INLINE void setupArgumentsExecState() - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - addCallArgument(arg3); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImmPtr arg3) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - addCallArgument(arg3); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, TrustedImmPtr arg3) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - addCallArgument(arg3); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - addCallArgument(arg3); - addCallArgument(arg4); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - addCallArgument(arg3); - addCallArgument(arg4); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, TrustedImm32 arg4) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - addCallArgument(arg3); - addCallArgument(arg4); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, GPRReg arg3, GPRReg arg4) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - addCallArgument(arg3); - addCallArgument(arg4); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5) - { - resetCallArguments(); - addCallArgument(GPRInfo::callFrameRegister); - addCallArgument(arg1); - addCallArgument(arg2); - addCallArgument(arg3); - addCallArgument(arg4); - addCallArgument(arg5); - } -#endif // !NUMBER_OF_ARGUMENT_REGISTERS - // These methods are suitable for any calling convention that provides for - // at least 4 argument registers, e.g. X86_64, ARMv7. -#if NUMBER_OF_ARGUMENT_REGISTERS >= 4 - template<GPRReg destA, GPRReg destB> - void setupTwoStubArgs(GPRReg srcA, GPRReg srcB) - { - // Assuming that srcA != srcB, there are 7 interesting states the registers may be in: - // (1) both are already in arg regs, the right way around. - // (2) both are already in arg regs, the wrong way around. - // (3) neither are currently in arg registers. - // (4) srcA in in its correct reg. - // (5) srcA in in the incorrect reg. - // (6) srcB in in its correct reg. - // (7) srcB in in the incorrect reg. - // - // The trivial approach is to simply emit two moves, to put srcA in place then srcB in - // place (the MacroAssembler will omit redundant moves). This apporach will be safe in - // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2 - // (requires a swap) and 7 (must move srcB first, to avoid trampling.) - - if (srcB != destA) { - // Handle the easy cases - two simple moves. - m_jit.move(srcA, destA); - m_jit.move(srcB, destB); - } else if (srcA != destB) { - // Handle the non-swap case - just put srcB in place first. - m_jit.move(srcB, destB); - m_jit.move(srcA, destA); - } else - m_jit.swap(destA, destB); - } -#if CPU(X86_64) - template<FPRReg destA, FPRReg destB> - void setupTwoStubArgs(FPRReg srcA, FPRReg srcB) - { - // Assuming that srcA != srcB, there are 7 interesting states the registers may be in: - // (1) both are already in arg regs, the right way around. - // (2) both are already in arg regs, the wrong way around. - // (3) neither are currently in arg registers. - // (4) srcA in in its correct reg. - // (5) srcA in in the incorrect reg. - // (6) srcB in in its correct reg. - // (7) srcB in in the incorrect reg. - // - // The trivial approach is to simply emit two moves, to put srcA in place then srcB in - // place (the MacroAssembler will omit redundant moves). This apporach will be safe in - // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2 - // (requires a swap) and 7 (must move srcB first, to avoid trampling.) - - if (srcB != destA) { - // Handle the easy cases - two simple moves. - m_jit.moveDouble(srcA, destA); - m_jit.moveDouble(srcB, destB); - return; - } - - if (srcA != destB) { - // Handle the non-swap case - just put srcB in place first. - m_jit.moveDouble(srcB, destB); - m_jit.moveDouble(srcA, destA); - return; - } - - ASSERT(srcB == destA && srcA == destB); - // Need to swap; pick a temporary register. - FPRReg temp; - if (destA != FPRInfo::argumentFPR3 && destA != FPRInfo::argumentFPR3) - temp = FPRInfo::argumentFPR3; - else if (destA != FPRInfo::argumentFPR2 && destA != FPRInfo::argumentFPR2) - temp = FPRInfo::argumentFPR2; - else { - ASSERT(destA != FPRInfo::argumentFPR1 && destA != FPRInfo::argumentFPR1); - temp = FPRInfo::argumentFPR1; - } - m_jit.moveDouble(destA, temp); - m_jit.moveDouble(destB, destA); - m_jit.moveDouble(temp, destB); - } -#endif - void setupStubArguments(GPRReg arg1, GPRReg arg2) - { - setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2); - } - void setupStubArguments(GPRReg arg1, GPRReg arg2, GPRReg arg3) - { - // If neither of arg2/arg3 are in our way, then we can move arg1 into place. - // Then we can use setupTwoStubArgs to fix arg2/arg3. - if (arg2 != GPRInfo::argumentGPR1 && arg3 != GPRInfo::argumentGPR1) { - m_jit.move(arg1, GPRInfo::argumentGPR1); - setupTwoStubArgs<GPRInfo::argumentGPR2, GPRInfo::argumentGPR3>(arg2, arg3); - return; - } - - // If neither of arg1/arg3 are in our way, then we can move arg2 into place. - // Then we can use setupTwoStubArgs to fix arg1/arg3. - if (arg1 != GPRInfo::argumentGPR2 && arg3 != GPRInfo::argumentGPR2) { - m_jit.move(arg2, GPRInfo::argumentGPR2); - setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3>(arg1, arg3); - return; - } - - // If neither of arg1/arg2 are in our way, then we can move arg3 into place. - // Then we can use setupTwoStubArgs to fix arg1/arg2. - if (arg1 != GPRInfo::argumentGPR3 && arg2 != GPRInfo::argumentGPR3) { - m_jit.move(arg3, GPRInfo::argumentGPR3); - setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2); - return; - } - - // If we get here, we haven't been able to move any of arg1/arg2/arg3. - // Since all three are blocked, then all three must already be in the argument register. - // But are they in the right ones? - - // First, ensure arg1 is in place. - if (arg1 != GPRInfo::argumentGPR1) { - m_jit.swap(arg1, GPRInfo::argumentGPR1); - - // If arg1 wasn't in argumentGPR1, one of arg2/arg3 must be. - ASSERT(arg2 == GPRInfo::argumentGPR1 || arg3 == GPRInfo::argumentGPR1); - // If arg2 was in argumentGPR1 it no longer is (due to the swap). - // Otherwise arg3 must have been. Mark him as moved. - if (arg2 == GPRInfo::argumentGPR1) - arg2 = arg1; - else - arg3 = arg1; - } - - // Either arg2 & arg3 need swapping, or we're all done. - ASSERT((arg2 == GPRInfo::argumentGPR2 || arg3 == GPRInfo::argumentGPR3) - || (arg2 == GPRInfo::argumentGPR3 || arg3 == GPRInfo::argumentGPR2)); - - if (arg2 != GPRInfo::argumentGPR2) - m_jit.swap(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3); - } - -#if CPU(X86_64) - ALWAYS_INLINE void setupArguments(FPRReg arg1) - { - m_jit.moveDouble(arg1, FPRInfo::argumentFPR0); - } - - ALWAYS_INLINE void setupArguments(FPRReg arg1, FPRReg arg2) - { - setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2); - } -#else - ALWAYS_INLINE void setupArguments(FPRReg arg1) - { - m_jit.assembler().vmov(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, arg1); - } - - ALWAYS_INLINE void setupArguments(FPRReg arg1, FPRReg arg2) - { - m_jit.assembler().vmov(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, arg1); - m_jit.assembler().vmov(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, arg2); - } -#endif - - ALWAYS_INLINE void setupArgumentsExecState() - { - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1) - { - m_jit.move(arg1, GPRInfo::argumentGPR1); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1) - { - m_jit.move(arg1, GPRInfo::argumentGPR1); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2) - { - setupStubArguments(arg1, arg2); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2) - { - m_jit.move(arg1, GPRInfo::argumentGPR1); - m_jit.move(arg2, GPRInfo::argumentGPR2); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2) - { - m_jit.move(arg2, GPRInfo::argumentGPR2); // Move this first, so setting arg1 does not trample! - m_jit.move(arg1, GPRInfo::argumentGPR1); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2) - { - m_jit.move(arg1, GPRInfo::argumentGPR1); - m_jit.move(arg2, GPRInfo::argumentGPR2); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2) - { - m_jit.move(arg1, GPRInfo::argumentGPR1); - m_jit.move(arg2, GPRInfo::argumentGPR2); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3) - { - setupStubArguments(arg1, arg2, arg3); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3) - { - setupStubArguments(arg1, arg2); - m_jit.move(arg3, GPRInfo::argumentGPR3); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, TrustedImmPtr arg3) - { - m_jit.move(arg1, GPRInfo::argumentGPR1); - m_jit.move(arg2, GPRInfo::argumentGPR2); - m_jit.move(arg3, GPRInfo::argumentGPR3); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImmPtr arg3) - { - setupStubArguments(arg1, arg2); - m_jit.move(arg3, GPRInfo::argumentGPR3); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, GPRReg arg3) - { - m_jit.move(arg1, GPRInfo::argumentGPR1); - m_jit.move(arg2, GPRInfo::argumentGPR2); - m_jit.move(arg3, GPRInfo::argumentGPR3); - m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - } - -#endif // NUMBER_OF_ARGUMENT_REGISTERS >= 4 - // These methods are suitable for any calling convention that provides for - // exactly 4 argument registers, e.g. ARMv7. -#if NUMBER_OF_ARGUMENT_REGISTERS == 4 - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4) - { - m_jit.poke(arg4); - setupArgumentsWithExecState(arg1, arg2, arg3); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, TrustedImm32 arg4) - { - m_jit.poke(arg4); - setupArgumentsWithExecState(arg1, arg2, arg3); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, GPRReg arg3, GPRReg arg4) - { - m_jit.poke(arg4); - setupArgumentsWithExecState(arg1, arg2, arg3); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4) - { - m_jit.poke(arg4); - setupArgumentsWithExecState(arg1, arg2, arg3); - } - - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5) - { - m_jit.poke(arg5, 1); - m_jit.poke(arg4); - setupArgumentsWithExecState(arg1, arg2, arg3); - } -#endif // NUMBER_OF_ARGUMENT_REGISTERS == 4 - // These methods add calls to C++ helper functions. // These methods are broadly value representation specific (i.e. // deal with the fact that a JSValue may be passed in one or two @@ -1519,314 +1078,314 @@ private: #if USE(JSVALUE64) JITCompiler::Call callOperation(J_DFGOperation_EP operation, GPRReg result, void* pointer) { - setupArgumentsWithExecState(TrustedImmPtr(pointer)); + m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer)); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(Z_DFGOperation_D operation, GPRReg result, FPRReg arg1) { - setupArguments(arg1); + m_jit.setupArguments(arg1); JITCompiler::Call call = m_jit.appendCall(operation); m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, result); return call; } JITCompiler::Call callOperation(J_DFGOperation_EGI operation, GPRReg result, GPRReg arg1, Identifier* identifier) { - setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EI operation, GPRReg result, Identifier* identifier) { - setupArgumentsWithExecState(TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EA operation, GPRReg result, GPRReg arg1) { - setupArgumentsWithExecState(arg1); + m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg result, void* pointer, size_t size) { - setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size)); + m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size)); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_ESS operation, GPRReg result, int startConstant, int numConstants) { - setupArgumentsWithExecState(Imm32(startConstant), Imm32(numConstants)); + m_jit.setupArgumentsWithExecState(Imm32(startConstant), Imm32(numConstants)); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EPP operation, GPRReg result, GPRReg arg1, void* pointer) { - setupArgumentsWithExecState(arg1, TrustedImmPtr(pointer)); + m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(pointer)); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_ECI operation, GPRReg result, GPRReg arg1, Identifier* identifier) { - setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EJI operation, GPRReg result, GPRReg arg1, Identifier* identifier) { - setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg result, GPRReg arg1, GPRReg arg2) { - setupArgumentsWithExecState(arg1, arg2); + m_jit.setupArgumentsWithExecState(arg1, arg2); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EP operation, GPRReg result, GPRReg arg1) { - setupArgumentsWithExecState(arg1); + m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(C_DFGOperation_E operation, GPRReg result) { - setupArgumentsExecState(); + m_jit.setupArgumentsExecState(); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(C_DFGOperation_EC operation, GPRReg result, GPRReg arg1) { - setupArgumentsWithExecState(arg1); + m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(C_DFGOperation_ECC operation, GPRReg result, GPRReg arg1, JSCell* cell) { - setupArgumentsWithExecState(arg1, TrustedImmPtr(cell)); + m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell)); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(S_DFGOperation_EJ operation, GPRReg result, GPRReg arg1) { - setupArgumentsWithExecState(arg1); + m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(S_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2) { - setupArgumentsWithExecState(arg1, arg2); + m_jit.setupArgumentsWithExecState(arg1, arg2); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EPP operation, GPRReg result, GPRReg arg1, GPRReg arg2) { - setupArgumentsWithExecState(arg1, arg2); + m_jit.setupArgumentsWithExecState(arg1, arg2); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, MacroAssembler::Imm32 imm) { - setupArgumentsWithExecState(arg1, MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm.m_value))))); + m_jit.setupArgumentsWithExecState(arg1, MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm.m_value))))); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg result, MacroAssembler::Imm32 imm, GPRReg arg2) { - setupArgumentsWithExecState(MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm.m_value)))), arg2); + m_jit.setupArgumentsWithExecState(MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm.m_value)))), arg2); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_ECJ operation, GPRReg result, GPRReg arg1, GPRReg arg2) { - setupArgumentsWithExecState(arg1, arg2); + m_jit.setupArgumentsWithExecState(arg1, arg2); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(V_DFGOperation_EJPP operation, GPRReg arg1, GPRReg arg2, void* pointer) { - setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(pointer)); + m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(pointer)); return appendCallWithExceptionCheck(operation); } JITCompiler::Call callOperation(V_DFGOperation_EJCI operation, GPRReg arg1, GPRReg arg2, Identifier* identifier) { - setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(identifier)); return appendCallWithExceptionCheck(operation); } JITCompiler::Call callOperation(V_DFGOperation_EJJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3) { - setupArgumentsWithExecState(arg1, arg2, arg3); + m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); return appendCallWithExceptionCheck(operation); } JITCompiler::Call callOperation(V_DFGOperation_EPZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3) { - setupArgumentsWithExecState(arg1, arg2, arg3); + m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); return appendCallWithExceptionCheck(operation); } JITCompiler::Call callOperation(V_DFGOperation_EAZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3) { - setupArgumentsWithExecState(arg1, arg2, arg3); + m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); return appendCallWithExceptionCheck(operation); } JITCompiler::Call callOperation(V_DFGOperation_ECJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3) { - setupArgumentsWithExecState(arg1, arg2, arg3); + m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); return appendCallWithExceptionCheck(operation); } JITCompiler::Call callOperation(D_DFGOperation_EJ operation, FPRReg result, GPRReg arg1) { - setupArgumentsWithExecState(arg1); + m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2) { - setupArguments(arg1, arg2); + m_jit.setupArguments(arg1, arg2); return appendCallSetResult(operation, result); } #else JITCompiler::Call callOperation(Z_DFGOperation_D operation, GPRReg result, FPRReg arg1) { - setupArguments(arg1); + m_jit.setupArguments(arg1); JITCompiler::Call call = m_jit.appendCall(operation); m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, result); return call; } JITCompiler::Call callOperation(J_DFGOperation_EP operation, GPRReg resultTag, GPRReg resultPayload, void* pointer) { - setupArgumentsWithExecState(TrustedImmPtr(pointer)); + m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EPP operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, void* pointer) { - setupArgumentsWithExecState(arg1, TrustedImmPtr(pointer)); + m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(pointer)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EGI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, Identifier* identifier) { - setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EP operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1) { - setupArgumentsWithExecState(arg1); + m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EI operation, GPRReg resultTag, GPRReg resultPayload, Identifier* identifier) { - setupArgumentsWithExecState(TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EA operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1) { - setupArgumentsWithExecState(arg1); + m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg resultTag, GPRReg resultPayload, void* pointer, size_t size) { - setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size)); + m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_ESS operation, GPRReg resultTag, GPRReg resultPayload, int startConstant, int numConstants) { - setupArgumentsWithExecState(TrustedImm32(startConstant), TrustedImm32(numConstants)); + m_jit.setupArgumentsWithExecState(TrustedImm32(startConstant), TrustedImm32(numConstants)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EJP operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, void* pointer) { - setupArgumentsWithExecState(arg1Payload, arg1Tag, ImmPtr(pointer)); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, ImmPtr(pointer)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EJP operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2) { - setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_ECI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, Identifier* identifier) { - setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EJI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, Identifier* identifier) { - setupArgumentsWithExecState(arg1Payload, arg1Tag, TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EJI operation, GPRReg resultTag, GPRReg resultPayload, int32_t arg1Tag, GPRReg arg1Payload, Identifier* identifier) { - setupArgumentsWithExecState(arg1Payload, TrustedImm32(arg1Tag), TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(arg1Payload, TrustedImm32(arg1Tag), TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2) { - setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload) { - setupArgumentsWithExecState(arg1Payload, arg1Tag); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(C_DFGOperation_E operation, GPRReg result) { - setupArgumentsExecState(); + m_jit.setupArgumentsExecState(); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(C_DFGOperation_EC operation, GPRReg result, GPRReg arg1) { - setupArgumentsWithExecState(arg1); + m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(C_DFGOperation_ECC operation, GPRReg result, GPRReg arg1, JSCell* cell) { - setupArgumentsWithExecState(arg1, TrustedImmPtr(cell)); + m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell)); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(S_DFGOperation_EJ operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload) { - setupArgumentsWithExecState(arg1Payload, arg1Tag); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(S_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload) { - setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2Payload, arg2Tag); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2Payload, arg2Tag); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload) { - setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2Payload, arg2Tag); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2Payload, arg2Tag); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, MacroAssembler::Imm32 imm) { - setupArgumentsWithExecState(arg1Payload, arg1Tag, imm, TrustedImm32(JSValue::Int32Tag)); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, imm, TrustedImm32(JSValue::Int32Tag)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, MacroAssembler::Imm32 imm, GPRReg arg2Tag, GPRReg arg2Payload) { - setupArgumentsWithExecState(imm, TrustedImm32(JSValue::Int32Tag), arg2Payload, arg2Tag); + m_jit.setupArgumentsWithExecState(imm, TrustedImm32(JSValue::Int32Tag), arg2Payload, arg2Tag); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_ECJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload) { - setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag); + m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(V_DFGOperation_EJPP operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2, void* pointer) { - setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2, TrustedImmPtr(pointer)); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2, TrustedImmPtr(pointer)); return appendCallWithExceptionCheck(operation); } JITCompiler::Call callOperation(V_DFGOperation_EJCI operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2, Identifier* identifier) { - setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2, TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2, TrustedImmPtr(identifier)); return appendCallWithExceptionCheck(operation); } JITCompiler::Call callOperation(V_DFGOperation_ECJJ operation, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload) { - setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, arg3Payload, arg3Tag); + m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, arg3Payload, arg3Tag); return appendCallWithExceptionCheck(operation); } JITCompiler::Call callOperation(V_DFGOperation_EPZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3Tag, GPRReg arg3Payload) { - setupArgumentsWithExecState(arg1, arg2, arg3Payload, arg3Tag); + m_jit.setupArgumentsWithExecState(arg1, arg2, arg3Payload, arg3Tag); return appendCallWithExceptionCheck(operation); } JITCompiler::Call callOperation(V_DFGOperation_EAZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3Tag, GPRReg arg3Payload) { - setupArgumentsWithExecState(arg1, arg2, arg3Payload, arg3Tag); + m_jit.setupArgumentsWithExecState(arg1, arg2, arg3Payload, arg3Tag); return appendCallWithExceptionCheck(operation); } JITCompiler::Call callOperation(D_DFGOperation_EJ operation, FPRReg result, GPRReg arg1Tag, GPRReg arg1Payload) { - setupArgumentsWithExecState(arg1Payload, arg1Tag); + m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2) { - setupArguments(arg1, arg2); + m_jit.setupArguments(arg1, arg2); return appendCallSetResult(operation, result); } #endif @@ -1834,7 +1393,11 @@ private: // These methods add call instructions, with optional exception checks & setting results. JITCompiler::Call appendCallWithExceptionCheck(const FunctionPtr& function) { - return m_jit.addExceptionCheck(m_jit.appendCall(function), at(m_compileIndex).codeOrigin); + CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin; + CallBeginToken token = m_jit.beginCall(codeOrigin); + JITCompiler::Call call = m_jit.appendCall(function); + m_jit.addExceptionCheck(call, codeOrigin, token); + return call; } JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, GPRReg result) { @@ -1842,26 +1405,10 @@ private: m_jit.move(GPRInfo::returnValueGPR, result); return call; } - void setupResults(GPRReg destA, GPRReg destB) - { - GPRReg srcA = GPRInfo::returnValueGPR; - GPRReg srcB = GPRInfo::returnValueGPR2; - - if (srcB != destA) { - // Handle the easy cases - two simple moves. - m_jit.move(srcA, destA); - m_jit.move(srcB, destB); - } else if (srcA != destB) { - // Handle the non-swap case - just put srcB in place first. - m_jit.move(srcB, destB); - m_jit.move(srcA, destA); - } else - m_jit.swap(destA, destB); - } JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, GPRReg result1, GPRReg result2) { JITCompiler::Call call = appendCallWithExceptionCheck(function); - setupResults(result1, result2); + m_jit.setupResults(result1, result2); return call; } #if CPU(X86) @@ -1975,6 +1522,8 @@ private: void compileUInt32ToNumber(Node&); void compileGetByValOnByteArray(Node&); void compilePutByValForByteArray(GPRReg base, GPRReg property, Node&); + void compileAdd(Node&); + void compileArithSub(Node&); void compileArithMul(Node&); void compileArithMod(Node&); void compileSoftModulo(Node&); @@ -1988,9 +1537,13 @@ private: SignedTypedArray, UnsignedTypedArray }; + enum TypedArrayRounding { + TruncateRounding, + ClampRounding + }; void compileGetIndexedPropertyStorage(Node&); void compileGetByValOnIntTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness); - void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness); + void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness, TypedArrayRounding = TruncateRounding); void compileGetByValOnFloatTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements); void compilePutByValForFloatTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index d6a82b1cc..e1f92ba9e 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -493,7 +493,7 @@ void SpeculativeJIT::nonSpeculativeUInt32ToNumber(Node& node) jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex); } -JITCompiler::Call SpeculativeJIT::cachedGetById(GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget) +JITCompiler::Call SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode) { m_jit.beginUninterruptedSequence(); JITCompiler::DataLabelPtr structureToCompare; @@ -513,24 +513,26 @@ JITCompiler::Call SpeculativeJIT::cachedGetById(GPRReg baseTagGPROrNone, GPRReg JITCompiler::Label slowCase = m_jit.label(); - silentSpillAllRegisters(resultTagGPR, resultPayloadGPR); + if (spillMode == NeedToSpill) + silentSpillAllRegisters(resultTagGPR, resultPayloadGPR); JITCompiler::Call functionCall; if (baseTagGPROrNone == InvalidGPRReg) functionCall = callOperation(operationGetByIdOptimize, resultTagGPR, resultPayloadGPR, JSValue::CellTag, basePayloadGPR, identifier(identifierNumber)); else functionCall = callOperation(operationGetByIdOptimize, resultTagGPR, resultPayloadGPR, baseTagGPROrNone, basePayloadGPR, identifier(identifierNumber)); - silentFillAllRegisters(resultTagGPR, resultPayloadGPR); + if (spillMode == NeedToSpill) + silentFillAllRegisters(resultTagGPR, resultPayloadGPR); done.link(&m_jit); JITCompiler::Label doneLabel = m_jit.label(); - m_jit.addPropertyAccess(PropertyAccessRecord(structureToCompare, functionCall, structureCheck, tagLoadWithPatch, payloadLoadWithPatch, slowCase, doneLabel, safeCast<int8_t>(basePayloadGPR), safeCast<int8_t>(resultTagGPR), safeCast<int8_t>(resultPayloadGPR), safeCast<int8_t>(scratchGPR))); + m_jit.addPropertyAccess(PropertyAccessRecord(codeOrigin, structureToCompare, functionCall, structureCheck, tagLoadWithPatch, payloadLoadWithPatch, slowCase, doneLabel, safeCast<int8_t>(basePayloadGPR), safeCast<int8_t>(resultTagGPR), safeCast<int8_t>(resultPayloadGPR), safeCast<int8_t>(scratchGPR), spillMode == NeedToSpill ? PropertyAccessRecord::RegistersInUse : PropertyAccessRecord::RegistersFlushed)); return functionCall; } -void SpeculativeJIT::cachedPutById(GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget) +void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget) { m_jit.beginUninterruptedSequence(); JITCompiler::DataLabelPtr structureToCompare; @@ -571,7 +573,7 @@ void SpeculativeJIT::cachedPutById(GPRReg basePayloadGPR, GPRReg valueTagGPR, GP done.link(&m_jit); JITCompiler::Label doneLabel = m_jit.label(); - m_jit.addPropertyAccess(PropertyAccessRecord(structureToCompare, functionCall, structureCheck, JITCompiler::DataLabelCompact(tagStoreWithPatch.label()), JITCompiler::DataLabelCompact(payloadStoreWithPatch.label()), slowCase, doneLabel, safeCast<int8_t>(basePayloadGPR), safeCast<int8_t>(valueTagGPR), safeCast<int8_t>(valuePayloadGPR), safeCast<int8_t>(scratchGPR))); + m_jit.addPropertyAccess(PropertyAccessRecord(codeOrigin, structureToCompare, functionCall, structureCheck, JITCompiler::DataLabelCompact(tagStoreWithPatch.label()), JITCompiler::DataLabelCompact(payloadStoreWithPatch.label()), slowCase, doneLabel, safeCast<int8_t>(basePayloadGPR), safeCast<int8_t>(valueTagGPR), safeCast<int8_t>(valuePayloadGPR), safeCast<int8_t>(scratchGPR))); } void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(NodeIndex operand, bool invert) @@ -950,8 +952,10 @@ void SpeculativeJIT::emitCall(Node& node) m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); + CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin; + CallBeginToken token = m_jit.nextCallBeginToken(codeOrigin); JITCompiler::Call fastCall = m_jit.nearCall(); - m_jit.notifyCall(fastCall, at(m_compileIndex).codeOrigin); + m_jit.notifyCall(fastCall, codeOrigin, token); JITCompiler::Jump done = m_jit.jump(); @@ -959,13 +963,17 @@ void SpeculativeJIT::emitCall(Node& node) m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); m_jit.poke(GPRInfo::argumentGPR0); - JITCompiler::Call slowCall = m_jit.addFastExceptionCheck(m_jit.appendCall(slowCallFunction), at(m_compileIndex).codeOrigin); + token = m_jit.beginCall(codeOrigin); + JITCompiler::Call slowCall = m_jit.appendCall(slowCallFunction); + m_jit.addFastExceptionCheck(slowCall, codeOrigin, token); m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); - m_jit.notifyCall(m_jit.call(GPRInfo::returnValueGPR), at(m_compileIndex).codeOrigin); + token = m_jit.nextCallBeginToken(codeOrigin); + JITCompiler::Call theCall = m_jit.call(GPRInfo::returnValueGPR); + m_jit.notifyCall(theCall, codeOrigin, token); done.link(&m_jit); - setupResults(resultPayloadGPR, resultTagGPR); + m_jit.setupResults(resultPayloadGPR, resultTagGPR); jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, DataFormatJS, UseChildrenCalledExplicitly); @@ -1878,133 +1886,17 @@ void SpeculativeJIT::compile(Node& node) } case ValueAdd: - case ArithAdd: { - if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { - if (isInt32Constant(node.child1())) { - int32_t imm1 = valueOfInt32Constant(node.child1()); - SpeculateIntegerOperand op2(this, node.child2()); - GPRTemporary result(this); - - if (nodeCanTruncateInteger(node.arithNodeFlags())) { - m_jit.move(op2.gpr(), result.gpr()); - m_jit.add32(Imm32(imm1), result.gpr()); - } else - speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr())); - - integerResult(result.gpr(), m_compileIndex); - break; - } - - if (isInt32Constant(node.child2())) { - SpeculateIntegerOperand op1(this, node.child1()); - int32_t imm2 = valueOfInt32Constant(node.child2()); - GPRTemporary result(this); - - if (nodeCanTruncateInteger(node.arithNodeFlags())) { - m_jit.move(op1.gpr(), result.gpr()); - m_jit.add32(Imm32(imm2), result.gpr()); - } else - speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr())); - - integerResult(result.gpr(), m_compileIndex); - break; - } - - SpeculateIntegerOperand op1(this, node.child1()); - SpeculateIntegerOperand op2(this, node.child2()); - GPRTemporary result(this, op1, op2); - - GPRReg gpr1 = op1.gpr(); - GPRReg gpr2 = op2.gpr(); - GPRReg gprResult = result.gpr(); - - if (nodeCanTruncateInteger(node.arithNodeFlags())) { - if (gpr1 == gprResult) - m_jit.add32(gpr2, gprResult); - else { - m_jit.move(gpr2, gprResult); - m_jit.add32(gpr1, gprResult); - } - } else { - MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult); - - if (gpr1 == gprResult) - speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2)); - else if (gpr2 == gprResult) - speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1)); - else - speculationCheck(Overflow, JSValueRegs(), NoNode, check); - } - - integerResult(gprResult, m_compileIndex); - break; - } - - if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) { - SpeculateDoubleOperand op1(this, node.child1()); - SpeculateDoubleOperand op2(this, node.child2()); - FPRTemporary result(this, op1, op2); - - FPRReg reg1 = op1.fpr(); - FPRReg reg2 = op2.fpr(); - m_jit.addDouble(reg1, reg2, result.fpr()); - - doubleResult(result.fpr(), m_compileIndex); - break; - } - - ASSERT(op == ValueAdd); - compileValueAdd(node); + case ArithAdd: + compileAdd(node); break; - } - - case ArithSub: { - if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { - if (isInt32Constant(node.child2())) { - SpeculateIntegerOperand op1(this, node.child1()); - int32_t imm2 = valueOfInt32Constant(node.child2()); - GPRTemporary result(this); - - if (nodeCanTruncateInteger(node.arithNodeFlags())) { - m_jit.move(op1.gpr(), result.gpr()); - m_jit.sub32(Imm32(imm2), result.gpr()); - } else - speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr())); - - integerResult(result.gpr(), m_compileIndex); - break; - } - - SpeculateIntegerOperand op1(this, node.child1()); - SpeculateIntegerOperand op2(this, node.child2()); - GPRTemporary result(this); - if (nodeCanTruncateInteger(node.arithNodeFlags())) { - m_jit.move(op1.gpr(), result.gpr()); - m_jit.sub32(op2.gpr(), result.gpr()); - } else - speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr())); - - integerResult(result.gpr(), m_compileIndex); - break; - } - - SpeculateDoubleOperand op1(this, node.child1()); - SpeculateDoubleOperand op2(this, node.child2()); - FPRTemporary result(this, op1); - - FPRReg reg1 = op1.fpr(); - FPRReg reg2 = op2.fpr(); - m_jit.subDouble(reg1, reg2, result.fpr()); - - doubleResult(result.fpr(), m_compileIndex); + case ArithSub: + compileArithSub(node); break; - } - case ArithMul: { + case ArithMul: compileArithMul(node); break; - } case ArithDiv: { if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { @@ -2292,7 +2184,14 @@ void SpeculativeJIT::compile(Node& node) return; break; } - + + if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + if (!m_compileOkay) + return; + break; + } + if (at(node.child1()).shouldSpeculateUint16Array()) { compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) @@ -2417,6 +2316,13 @@ void SpeculativeJIT::compile(Node& node) break; } + if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); + if (!m_compileOkay) + return; + break; + } + if (at(node.child1()).shouldSpeculateUint16Array()) { compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) @@ -2552,7 +2458,14 @@ void SpeculativeJIT::compile(Node& node) return; break; } - + + if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray, ClampRounding); + if (!m_compileOkay) + return; + break; + } + if (at(node.child1()).shouldSpeculateUint16Array()) { compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), NoTypedArraySpecCheck, UnsignedTypedArray); if (!m_compileOkay) @@ -3126,7 +3039,7 @@ void SpeculativeJIT::compile(Node& node) base.use(); - cachedGetById(InvalidGPRReg, baseGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber()); + cachedGetById(node.codeOrigin, InvalidGPRReg, baseGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber()); jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly); break; @@ -3151,7 +3064,58 @@ void SpeculativeJIT::compile(Node& node) JITCompiler::Jump notCell = m_jit.branch32(JITCompiler::NotEqual, baseTagGPR, TrustedImm32(JSValue::CellTag)); - cachedGetById(baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber(), notCell); + cachedGetById(node.codeOrigin, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber(), notCell); + + jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly); + break; + } + + case GetByIdFlush: { + if (!node.prediction()) { + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + break; + } + + if (isCellPrediction(at(node.child1()).prediction())) { + SpeculateCellOperand base(this, node.child1()); + + GPRReg baseGPR = base.gpr(); + + GPRResult resultTag(this); + GPRResult2 resultPayload(this); + GPRReg resultTagGPR = resultTag.gpr(); + GPRReg resultPayloadGPR = resultPayload.gpr(); + + GPRReg scratchGPR = selectScratchGPR(baseGPR, resultTagGPR, resultPayloadGPR); + + base.use(); + + flushRegisters(); + + cachedGetById(node.codeOrigin, InvalidGPRReg, baseGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber(), JITCompiler::Jump(), DontSpill); + + jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly); + break; + } + + JSValueOperand base(this, node.child1()); + GPRReg baseTagGPR = base.tagGPR(); + GPRReg basePayloadGPR = base.payloadGPR(); + + GPRResult resultTag(this); + GPRResult2 resultPayload(this); + GPRReg resultTagGPR = resultTag.gpr(); + GPRReg resultPayloadGPR = resultPayload.gpr(); + + GPRReg scratchGPR = selectScratchGPR(baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR); + + base.use(); + + flushRegisters(); + + JITCompiler::Jump notCell = m_jit.branch32(JITCompiler::NotEqual, baseTagGPR, TrustedImm32(JSValue::CellTag)); + + cachedGetById(node.codeOrigin, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber(), notCell, DontSpill); jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly); break; @@ -3224,6 +3188,10 @@ void SpeculativeJIT::compile(Node& node) compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type)); break; } + case GetUint8ClampedArrayLength: { + compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type)); + break; + } case GetUint16ArrayLength: { compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type)); break; @@ -3372,7 +3340,7 @@ void SpeculativeJIT::compile(Node& node) base.use(); value.use(); - cachedPutById(baseGPR, valueTagGPR, valuePayloadGPR, node.child2(), scratchGPR, node.identifierNumber(), NotDirect); + cachedPutById(node.codeOrigin, baseGPR, valueTagGPR, valuePayloadGPR, node.child2(), scratchGPR, node.identifierNumber(), NotDirect); noResult(m_compileIndex, UseChildrenCalledExplicitly); break; @@ -3391,7 +3359,7 @@ void SpeculativeJIT::compile(Node& node) base.use(); value.use(); - cachedPutById(baseGPR, valueTagGPR, valuePayloadGPR, node.child2(), scratchGPR, node.identifierNumber(), Direct); + cachedPutById(node.codeOrigin, baseGPR, valueTagGPR, valuePayloadGPR, node.child2(), scratchGPR, node.identifierNumber(), Direct); noResult(m_compileIndex, UseChildrenCalledExplicitly); break; diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index 7e36165f3..139dedded 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -477,7 +477,7 @@ void SpeculativeJIT::nonSpeculativeUInt32ToNumber(Node& node) jsValueResult(result.gpr(), m_compileIndex); } -JITCompiler::Call SpeculativeJIT::cachedGetById(GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget) +JITCompiler::Call SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode) { JITCompiler::DataLabelPtr structureToCompare; JITCompiler::Jump structureCheck = m_jit.branchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1))); @@ -494,23 +494,25 @@ JITCompiler::Call SpeculativeJIT::cachedGetById(GPRReg baseGPR, GPRReg resultGPR JITCompiler::Label slowCase = m_jit.label(); - silentSpillAllRegisters(resultGPR); + if (spillMode == NeedToSpill) + silentSpillAllRegisters(resultGPR); JITCompiler::Call functionCall = callOperation(operationGetByIdOptimize, resultGPR, baseGPR, identifier(identifierNumber)); - silentFillAllRegisters(resultGPR); + if (spillMode == NeedToSpill) + silentFillAllRegisters(resultGPR); done.link(&m_jit); JITCompiler::Label doneLabel = m_jit.label(); - m_jit.addPropertyAccess(PropertyAccessRecord(structureToCompare, functionCall, structureCheck, loadWithPatch, slowCase, doneLabel, safeCast<int8_t>(baseGPR), safeCast<int8_t>(resultGPR), safeCast<int8_t>(scratchGPR))); + m_jit.addPropertyAccess(PropertyAccessRecord(codeOrigin, structureToCompare, functionCall, structureCheck, loadWithPatch, slowCase, doneLabel, safeCast<int8_t>(baseGPR), safeCast<int8_t>(resultGPR), safeCast<int8_t>(scratchGPR), spillMode == NeedToSpill ? PropertyAccessRecord::RegistersInUse : PropertyAccessRecord::RegistersFlushed)); - if (scratchGPR != resultGPR && scratchGPR != InvalidGPRReg) + if (scratchGPR != resultGPR && scratchGPR != InvalidGPRReg && spillMode == NeedToSpill) unlock(scratchGPR); return functionCall; } -void SpeculativeJIT::cachedPutById(GPRReg baseGPR, GPRReg valueGPR, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget) +void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg valueGPR, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget) { JITCompiler::DataLabelPtr structureToCompare; @@ -549,7 +551,7 @@ void SpeculativeJIT::cachedPutById(GPRReg baseGPR, GPRReg valueGPR, NodeIndex va done.link(&m_jit); JITCompiler::Label doneLabel = m_jit.label(); - m_jit.addPropertyAccess(PropertyAccessRecord(structureToCompare, functionCall, structureCheck, JITCompiler::DataLabelCompact(storeWithPatch.label()), slowCase, doneLabel, safeCast<int8_t>(baseGPR), safeCast<int8_t>(valueGPR), safeCast<int8_t>(scratchGPR))); + m_jit.addPropertyAccess(PropertyAccessRecord(codeOrigin, structureToCompare, functionCall, structureCheck, JITCompiler::DataLabelCompact(storeWithPatch.label()), slowCase, doneLabel, safeCast<int8_t>(baseGPR), safeCast<int8_t>(valueGPR), safeCast<int8_t>(scratchGPR))); } void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(NodeIndex operand, bool invert) @@ -951,17 +953,23 @@ void SpeculativeJIT::emitCall(Node& node) m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); + CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin; + CallBeginToken token = m_jit.nextCallBeginToken(codeOrigin); JITCompiler::Call fastCall = m_jit.nearCall(); - m_jit.notifyCall(fastCall, at(m_compileIndex).codeOrigin); + m_jit.notifyCall(fastCall, codeOrigin, token); JITCompiler::Jump done = m_jit.jump(); slowPath.link(&m_jit); m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - JITCompiler::Call slowCall = m_jit.addFastExceptionCheck(m_jit.appendCall(slowCallFunction), at(m_compileIndex).codeOrigin); + token = m_jit.beginCall(codeOrigin); + JITCompiler::Call slowCall = m_jit.appendCall(slowCallFunction); + m_jit.addFastExceptionCheck(slowCall, codeOrigin, token); m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); - m_jit.notifyCall(m_jit.call(GPRInfo::returnValueGPR), at(m_compileIndex).codeOrigin); + token = m_jit.nextCallBeginToken(codeOrigin); + JITCompiler::Call theCall = m_jit.call(GPRInfo::returnValueGPR); + m_jit.notifyCall(theCall, codeOrigin, token); done.link(&m_jit); @@ -1957,133 +1965,17 @@ void SpeculativeJIT::compile(Node& node) } case ValueAdd: - case ArithAdd: { - if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { - if (isInt32Constant(node.child1())) { - int32_t imm1 = valueOfInt32Constant(node.child1()); - SpeculateIntegerOperand op2(this, node.child2()); - GPRTemporary result(this); - - if (nodeCanTruncateInteger(node.arithNodeFlags())) { - m_jit.move(op2.gpr(), result.gpr()); - m_jit.add32(Imm32(imm1), result.gpr()); - } else - speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr())); - - integerResult(result.gpr(), m_compileIndex); - break; - } - - if (isInt32Constant(node.child2())) { - SpeculateIntegerOperand op1(this, node.child1()); - int32_t imm2 = valueOfInt32Constant(node.child2()); - GPRTemporary result(this); - - if (nodeCanTruncateInteger(node.arithNodeFlags())) { - m_jit.move(op1.gpr(), result.gpr()); - m_jit.add32(Imm32(imm2), result.gpr()); - } else - speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr())); - - integerResult(result.gpr(), m_compileIndex); - break; - } - - SpeculateIntegerOperand op1(this, node.child1()); - SpeculateIntegerOperand op2(this, node.child2()); - GPRTemporary result(this, op1, op2); - - GPRReg gpr1 = op1.gpr(); - GPRReg gpr2 = op2.gpr(); - GPRReg gprResult = result.gpr(); - - if (nodeCanTruncateInteger(node.arithNodeFlags())) { - if (gpr1 == gprResult) - m_jit.add32(gpr2, gprResult); - else { - m_jit.move(gpr2, gprResult); - m_jit.add32(gpr1, gprResult); - } - } else { - MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult); - - if (gpr1 == gprResult) - speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2)); - else if (gpr2 == gprResult) - speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1)); - else - speculationCheck(Overflow, JSValueRegs(), NoNode, check); - } - - integerResult(gprResult, m_compileIndex); - break; - } - - if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) { - SpeculateDoubleOperand op1(this, node.child1()); - SpeculateDoubleOperand op2(this, node.child2()); - FPRTemporary result(this, op1, op2); - - FPRReg reg1 = op1.fpr(); - FPRReg reg2 = op2.fpr(); - m_jit.addDouble(reg1, reg2, result.fpr()); - - doubleResult(result.fpr(), m_compileIndex); - break; - } - - ASSERT(op == ValueAdd); - compileValueAdd(node); + case ArithAdd: + compileAdd(node); break; - } - - case ArithSub: { - if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { - if (isInt32Constant(node.child2())) { - SpeculateIntegerOperand op1(this, node.child1()); - int32_t imm2 = valueOfInt32Constant(node.child2()); - GPRTemporary result(this); - - if (nodeCanTruncateInteger(node.arithNodeFlags())) { - m_jit.move(op1.gpr(), result.gpr()); - m_jit.sub32(Imm32(imm2), result.gpr()); - } else - speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr())); - - integerResult(result.gpr(), m_compileIndex); - break; - } - - SpeculateIntegerOperand op1(this, node.child1()); - SpeculateIntegerOperand op2(this, node.child2()); - GPRTemporary result(this); - - if (nodeCanTruncateInteger(node.arithNodeFlags())) { - m_jit.move(op1.gpr(), result.gpr()); - m_jit.sub32(op2.gpr(), result.gpr()); - } else - speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr())); - integerResult(result.gpr(), m_compileIndex); - break; - } - - SpeculateDoubleOperand op1(this, node.child1()); - SpeculateDoubleOperand op2(this, node.child2()); - FPRTemporary result(this, op1); - - FPRReg reg1 = op1.fpr(); - FPRReg reg2 = op2.fpr(); - m_jit.subDouble(reg1, reg2, result.fpr()); - - doubleResult(result.fpr(), m_compileIndex); + case ArithSub: + compileArithSub(node); break; - } - case ArithMul: { + case ArithMul: compileArithMul(node); break; - } case ArithDiv: { if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { @@ -2346,7 +2238,14 @@ void SpeculativeJIT::compile(Node& node) return; break; } - + + if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + if (!m_compileOkay) + return; + break; + } + if (at(node.child1()).shouldSpeculateUint16Array()) { compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) @@ -2458,7 +2357,12 @@ void SpeculativeJIT::compile(Node& node) return; break; } - + + if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); + break; + } + if (at(node.child1()).shouldSpeculateUint16Array()) { compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) @@ -2591,7 +2495,14 @@ void SpeculativeJIT::compile(Node& node) return; break; } - + + if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray, ClampRounding); + if (!m_compileOkay) + return; + break; + } + if (at(node.child1()).shouldSpeculateUint16Array()) { compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), NoTypedArraySpecCheck, UnsignedTypedArray); if (!m_compileOkay) @@ -3123,7 +3034,7 @@ void SpeculativeJIT::compile(Node& node) base.use(); - cachedGetById(baseGPR, resultGPR, scratchGPR, node.identifierNumber()); + cachedGetById(node.codeOrigin, baseGPR, resultGPR, scratchGPR, node.identifierNumber()); jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly); break; @@ -3145,7 +3056,53 @@ void SpeculativeJIT::compile(Node& node) JITCompiler::Jump notCell = m_jit.branchTestPtr(JITCompiler::NonZero, baseGPR, GPRInfo::tagMaskRegister); - cachedGetById(baseGPR, resultGPR, scratchGPR, node.identifierNumber(), notCell); + cachedGetById(node.codeOrigin, baseGPR, resultGPR, scratchGPR, node.identifierNumber(), notCell); + + jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly); + + break; + } + + case GetByIdFlush: { + if (!node.prediction()) { + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + break; + } + + if (isCellPrediction(at(node.child1()).prediction())) { + SpeculateCellOperand base(this, node.child1()); + GPRReg baseGPR = base.gpr(); + + GPRResult result(this); + + GPRReg resultGPR = result.gpr(); + + GPRReg scratchGPR = selectScratchGPR(baseGPR, resultGPR); + + base.use(); + + flushRegisters(); + + cachedGetById(node.codeOrigin, baseGPR, resultGPR, scratchGPR, node.identifierNumber(), JITCompiler::Jump(), DontSpill); + + jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly); + break; + } + + JSValueOperand base(this, node.child1()); + GPRReg baseGPR = base.gpr(); + + GPRResult result(this); + GPRReg resultGPR = result.gpr(); + + GPRReg scratchGPR = selectScratchGPR(baseGPR, resultGPR); + + base.use(); + flushRegisters(); + + JITCompiler::Jump notCell = m_jit.branchTestPtr(JITCompiler::NonZero, baseGPR, GPRInfo::tagMaskRegister); + + cachedGetById(node.codeOrigin, baseGPR, resultGPR, scratchGPR, node.identifierNumber(), notCell, DontSpill); jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly); @@ -3219,6 +3176,10 @@ void SpeculativeJIT::compile(Node& node) compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type)); break; } + case GetUint8ClampedArrayLength: { + compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type)); + break; + } case GetUint16ArrayLength: { compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type)); break; @@ -3359,7 +3320,7 @@ void SpeculativeJIT::compile(Node& node) base.use(); value.use(); - cachedPutById(baseGPR, valueGPR, node.child2(), scratchGPR, node.identifierNumber(), NotDirect); + cachedPutById(node.codeOrigin, baseGPR, valueGPR, node.child2(), scratchGPR, node.identifierNumber(), NotDirect); noResult(m_compileIndex, UseChildrenCalledExplicitly); break; @@ -3377,7 +3338,7 @@ void SpeculativeJIT::compile(Node& node) base.use(); value.use(); - cachedPutById(baseGPR, valueGPR, node.child2(), scratchGPR, node.identifierNumber(), Direct); + cachedPutById(node.codeOrigin, baseGPR, valueGPR, node.child2(), scratchGPR, node.identifierNumber(), Direct); noResult(m_compileIndex, UseChildrenCalledExplicitly); break; diff --git a/Source/JavaScriptCore/dfg/DFGThunks.cpp b/Source/JavaScriptCore/dfg/DFGThunks.cpp index fddb656cc..d7c3fab23 100644 --- a/Source/JavaScriptCore/dfg/DFGThunks.cpp +++ b/Source/JavaScriptCore/dfg/DFGThunks.cpp @@ -66,7 +66,7 @@ MacroAssemblerCodeRef osrExitGenerationThunkGenerator(JSGlobalData* globalData) jit.jump(MacroAssembler::AbsoluteAddress(&globalData->osrExitJumpDestination)); - LinkBuffer patchBuffer(*globalData, &jit); + LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); patchBuffer.link(functionCall, compileOSRExit); diff --git a/Source/JavaScriptCore/heap/AllocationSpace.cpp b/Source/JavaScriptCore/heap/AllocationSpace.cpp deleted file mode 100644 index e363de274..000000000 --- a/Source/JavaScriptCore/heap/AllocationSpace.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include "AllocationSpace.h" - -#include "Heap.h" - -#define COLLECT_ON_EVERY_ALLOCATION 0 - -namespace JSC { - -inline void* AllocationSpace::tryAllocate(MarkedSpace::SizeClass& sizeClass) -{ - m_heap->m_operationInProgress = Allocation; - void* result = m_markedSpace.allocate(sizeClass); - m_heap->m_operationInProgress = NoOperation; - return result; -} - -void* AllocationSpace::allocateSlowCase(MarkedSpace::SizeClass& sizeClass) -{ -#if COLLECT_ON_EVERY_ALLOCATION - m_heap->collectAllGarbage(); - ASSERT(m_heap->m_operationInProgress == NoOperation); -#endif - - void* result = tryAllocate(sizeClass); - - if (LIKELY(result != 0)) - return result; - - AllocationEffort allocationEffort; - - if (( -#if ENABLE(GGC) - m_markedSpace.nurseryWaterMark() < m_heap->m_minBytesPerCycle -#else - m_markedSpace.waterMark() < m_markedSpace.highWaterMark() -#endif - ) || !m_heap->m_isSafeToCollect) - allocationEffort = AllocationMustSucceed; - else - allocationEffort = AllocationCanFail; - - MarkedBlock* block = allocateBlock(sizeClass.cellSize, allocationEffort); - if (block) { - m_markedSpace.addBlock(sizeClass, block); - void* result = tryAllocate(sizeClass); - ASSERT(result); - return result; - } - - m_heap->collect(Heap::DoNotSweep); - - result = tryAllocate(sizeClass); - - if (result) - return result; - - ASSERT(m_markedSpace.waterMark() < m_markedSpace.highWaterMark()); - - m_markedSpace.addBlock(sizeClass, allocateBlock(sizeClass.cellSize, AllocationMustSucceed)); - - result = tryAllocate(sizeClass); - ASSERT(result); - return result; -} - -MarkedBlock* AllocationSpace::allocateBlock(size_t cellSize, AllocationSpace::AllocationEffort allocationEffort) -{ - MarkedBlock* block; - - { - MutexLocker locker(m_heap->m_freeBlockLock); - if (m_heap->m_numberOfFreeBlocks) { - block = m_heap->m_freeBlocks.removeHead(); - ASSERT(block); - m_heap->m_numberOfFreeBlocks--; - } else - block = 0; - } - if (block) - block = MarkedBlock::recycle(block, cellSize); - else if (allocationEffort == AllocationCanFail) - return 0; - else - block = MarkedBlock::create(m_heap, cellSize); - - m_blocks.add(block); - - return block; -} - -void AllocationSpace::freeBlocks(MarkedBlock* head) -{ - MarkedBlock* next; - for (MarkedBlock* block = head; block; block = next) { - next = block->next(); - - m_blocks.remove(block); - block->sweep(); - MutexLocker locker(m_heap->m_freeBlockLock); - m_heap->m_freeBlocks.append(block); - m_heap->m_numberOfFreeBlocks++; - } -} - -class TakeIfUnmarked { -public: - typedef MarkedBlock* ReturnType; - - TakeIfUnmarked(MarkedSpace*); - void operator()(MarkedBlock*); - ReturnType returnValue(); - -private: - MarkedSpace* m_markedSpace; - DoublyLinkedList<MarkedBlock> m_empties; -}; - -inline TakeIfUnmarked::TakeIfUnmarked(MarkedSpace* newSpace) - : m_markedSpace(newSpace) -{ -} - -inline void TakeIfUnmarked::operator()(MarkedBlock* block) -{ - if (!block->markCountIsZero()) - return; - - m_markedSpace->removeBlock(block); - m_empties.append(block); -} - -inline TakeIfUnmarked::ReturnType TakeIfUnmarked::returnValue() -{ - return m_empties.head(); -} - -void AllocationSpace::shrink() -{ - // We record a temporary list of empties to avoid modifying m_blocks while iterating it. - TakeIfUnmarked takeIfUnmarked(&m_markedSpace); - freeBlocks(forEachBlock(takeIfUnmarked)); -} - -#if ENABLE(GGC) -class GatherDirtyCells { - WTF_MAKE_NONCOPYABLE(GatherDirtyCells); -public: - typedef void* ReturnType; - - explicit GatherDirtyCells(MarkedBlock::DirtyCellVector*); - void operator()(MarkedBlock*); - ReturnType returnValue() { return 0; } - -private: - MarkedBlock::DirtyCellVector* m_dirtyCells; -}; - -inline GatherDirtyCells::GatherDirtyCells(MarkedBlock::DirtyCellVector* dirtyCells) - : m_dirtyCells(dirtyCells) -{ -} - -inline void GatherDirtyCells::operator()(MarkedBlock* block) -{ - block->gatherDirtyCells(*m_dirtyCells); -} - -void AllocationSpace::gatherDirtyCells(MarkedBlock::DirtyCellVector& dirtyCells) -{ - GatherDirtyCells gatherDirtyCells(&dirtyCells); - forEachBlock(gatherDirtyCells); -} -#endif - -} diff --git a/Source/JavaScriptCore/heap/AllocationSpace.h b/Source/JavaScriptCore/heap/AllocationSpace.h deleted file mode 100644 index 550cb9aa3..000000000 --- a/Source/JavaScriptCore/heap/AllocationSpace.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef AllocationSpace_h -#define AllocationSpace_h - -#include "MarkedBlockSet.h" -#include "MarkedSpace.h" - -#include <wtf/HashSet.h> - -namespace JSC { - -class Heap; -class MarkedBlock; - -class AllocationSpace { -public: - AllocationSpace(Heap* heap) - : m_heap(heap) - , m_markedSpace(heap) - { - } - - typedef HashSet<MarkedBlock*>::iterator BlockIterator; - - MarkedBlockSet& blocks() { return m_blocks; } - MarkedSpace::SizeClass& sizeClassFor(size_t bytes) { return m_markedSpace.sizeClassFor(bytes); } - void setHighWaterMark(size_t bytes) { m_markedSpace.setHighWaterMark(bytes); } - size_t highWaterMark() { return m_markedSpace.highWaterMark(); } - -#if ENABLE(GGC) - void gatherDirtyCells(MarkedBlock::DirtyCellVector&); -#endif - - template<typename Functor> typename Functor::ReturnType forEachCell(Functor&); - template<typename Functor> typename Functor::ReturnType forEachCell(); - template<typename Functor> typename Functor::ReturnType forEachBlock(Functor&); - template<typename Functor> typename Functor::ReturnType forEachBlock(); - - void canonicalizeCellLivenessData() { m_markedSpace.canonicalizeCellLivenessData(); } - void resetAllocator() { m_markedSpace.resetAllocator(); } - - void* allocate(size_t); - void freeBlocks(MarkedBlock*); - void shrink(); - -private: - enum AllocationEffort { AllocationMustSucceed, AllocationCanFail }; - - void* allocate(MarkedSpace::SizeClass&); - void* tryAllocate(MarkedSpace::SizeClass&); - void* allocateSlowCase(MarkedSpace::SizeClass&); - MarkedBlock* allocateBlock(size_t cellSize, AllocationEffort); - - Heap* m_heap; - MarkedSpace m_markedSpace; - MarkedBlockSet m_blocks; -}; - -template<typename Functor> inline typename Functor::ReturnType AllocationSpace::forEachCell(Functor& functor) -{ - canonicalizeCellLivenessData(); - - BlockIterator end = m_blocks.set().end(); - for (BlockIterator it = m_blocks.set().begin(); it != end; ++it) - (*it)->forEachCell(functor); - return functor.returnValue(); -} - -template<typename Functor> inline typename Functor::ReturnType AllocationSpace::forEachCell() -{ - Functor functor; - return forEachCell(functor); -} - -template<typename Functor> inline typename Functor::ReturnType AllocationSpace::forEachBlock(Functor& functor) -{ - BlockIterator end = m_blocks.set().end(); - for (BlockIterator it = m_blocks.set().begin(); it != end; ++it) - functor(*it); - return functor.returnValue(); -} - -template<typename Functor> inline typename Functor::ReturnType AllocationSpace::forEachBlock() -{ - Functor functor; - return forEachBlock(functor); -} - -inline void* AllocationSpace::allocate(MarkedSpace::SizeClass& sizeClass) -{ - // This is a light-weight fast path to cover the most common case. - MarkedBlock::FreeCell* firstFreeCell = sizeClass.firstFreeCell; - if (UNLIKELY(!firstFreeCell)) - return allocateSlowCase(sizeClass); - - sizeClass.firstFreeCell = firstFreeCell->next; - return firstFreeCell; -} - -inline void* AllocationSpace::allocate(size_t bytes) -{ - MarkedSpace::SizeClass& sizeClass = sizeClassFor(bytes); - return allocate(sizeClass); -} - -} - -#endif diff --git a/Source/JavaScriptCore/heap/BumpBlock.h b/Source/JavaScriptCore/heap/BumpBlock.h new file mode 100644 index 000000000..b9f271ca8 --- /dev/null +++ b/Source/JavaScriptCore/heap/BumpBlock.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 BumpBlock_h +#define BumpBlock_h + +#include "HeapBlock.h" + +namespace JSC { + +class BumpSpace; + +class BumpBlock : public HeapBlock { + friend class BumpSpace; +public: + BumpBlock(PageAllocationAligned& allocation) + : HeapBlock(allocation) + , m_offset(m_payload) + , m_isPinned(false) + { + } + +private: + void* m_offset; + uintptr_t m_isPinned; + char m_payload[1]; +}; + +} // namespace JSC + +#endif diff --git a/Source/JavaScriptCore/heap/BumpSpace.cpp b/Source/JavaScriptCore/heap/BumpSpace.cpp new file mode 100644 index 000000000..4eb0284dd --- /dev/null +++ b/Source/JavaScriptCore/heap/BumpSpace.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "BumpSpace.h" + +#include "BumpSpaceInlineMethods.h" + +namespace JSC { + +CheckedBoolean BumpSpace::tryAllocateSlowCase(size_t bytes, void** outPtr) +{ + if (isOversize(bytes)) + return tryAllocateOversize(bytes, outPtr); + + m_totalMemoryUtilized += static_cast<size_t>(static_cast<char*>(m_currentBlock->m_offset) - m_currentBlock->m_payload); + if (!addNewBlock()) { + *outPtr = 0; + return false; + } + m_toSpaceFilter.add(reinterpret_cast<Bits>(m_currentBlock)); + m_toSpaceSet.add(m_currentBlock); + *outPtr = allocateFromBlock(m_currentBlock, bytes); + return true; +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/heap/BumpSpace.h b/Source/JavaScriptCore/heap/BumpSpace.h new file mode 100644 index 000000000..30e6b74fe --- /dev/null +++ b/Source/JavaScriptCore/heap/BumpSpace.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 BumpSpace_h +#define BumpSpace_h + +#include "HeapBlock.h" +#include "TinyBloomFilter.h" +#include <wtf/Assertions.h> +#include <wtf/CheckedBoolean.h> +#include <wtf/DoublyLinkedList.h> +#include <wtf/HashSet.h> +#include <wtf/OSAllocator.h> +#include <wtf/PageAllocationAligned.h> +#include <wtf/StdLibExtras.h> +#include <wtf/ThreadingPrimitives.h> + +namespace JSC { + +class Heap; +class BumpBlock; +class HeapBlock; + +class BumpSpace { + friend class SlotVisitor; +public: + BumpSpace(Heap*); + void init(); + + CheckedBoolean tryAllocate(size_t, void**); + CheckedBoolean tryReallocate(void**, size_t, size_t); + + void startedCopying(); + void doneCopying(); + bool isInCopyPhase() { return m_inCopyingPhase; } + + void pin(BumpBlock*); + bool isPinned(void*); + + bool contains(void*, BumpBlock*&); + + size_t totalMemoryAllocated() { return m_totalMemoryAllocated; } + size_t totalMemoryUtilized() { return m_totalMemoryUtilized; } + + static BumpBlock* blockFor(void*); + +private: + CheckedBoolean tryAllocateSlowCase(size_t, void**); + CheckedBoolean addNewBlock(); + CheckedBoolean allocateNewBlock(BumpBlock**); + bool fitsInCurrentBlock(size_t); + + static void* allocateFromBlock(BumpBlock*, size_t); + CheckedBoolean tryAllocateOversize(size_t, void**); + CheckedBoolean tryReallocateOversize(void**, size_t, size_t); + + static bool isOversize(size_t); + + CheckedBoolean borrowBlock(BumpBlock**); + CheckedBoolean getFreshBlock(AllocationEffort, BumpBlock**); + void doneFillingBlock(BumpBlock*); + void recycleBlock(BumpBlock*); + static bool fitsInBlock(BumpBlock*, size_t); + static BumpBlock* oversizeBlockFor(void* ptr); + + Heap* m_heap; + + BumpBlock* m_currentBlock; + + TinyBloomFilter m_toSpaceFilter; + TinyBloomFilter m_oversizeFilter; + HashSet<BumpBlock*> m_toSpaceSet; + + Mutex m_toSpaceLock; + Mutex m_memoryStatsLock; + + DoublyLinkedList<HeapBlock>* m_toSpace; + DoublyLinkedList<HeapBlock>* m_fromSpace; + + DoublyLinkedList<HeapBlock> m_blocks1; + DoublyLinkedList<HeapBlock> m_blocks2; + DoublyLinkedList<HeapBlock> m_oversizeBlocks; + + size_t m_totalMemoryAllocated; + size_t m_totalMemoryUtilized; + + bool m_inCopyingPhase; + + Mutex m_loanedBlocksLock; + ThreadCondition m_loanedBlocksCondition; + size_t m_numberOfLoanedBlocks; + + static const size_t s_blockSize = 64 * KB; + static const size_t s_maxAllocationSize = 32 * KB; + static const size_t s_pageSize = 4 * KB; + static const size_t s_pageMask = ~(s_pageSize - 1); + static const size_t s_initialBlockNum = 16; + static const size_t s_blockMask = ~(s_blockSize - 1); +}; + +} // namespace JSC + +#endif diff --git a/Source/JavaScriptCore/heap/BumpSpaceInlineMethods.h b/Source/JavaScriptCore/heap/BumpSpaceInlineMethods.h new file mode 100644 index 000000000..3454631b0 --- /dev/null +++ b/Source/JavaScriptCore/heap/BumpSpaceInlineMethods.h @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 BumpSpaceInlineMethods_h +#define BumpSpaceInlineMethods_h + +#include "BumpBlock.h" +#include "BumpSpace.h" +#include "Heap.h" +#include "HeapBlock.h" +#include "JSGlobalData.h" +#include <wtf/CheckedBoolean.h> + +namespace JSC { + +inline BumpSpace::BumpSpace(Heap* heap) + : m_heap(heap) + , m_currentBlock(0) + , m_toSpace(0) + , m_fromSpace(0) + , m_totalMemoryAllocated(0) + , m_totalMemoryUtilized(0) + , m_inCopyingPhase(false) + , m_numberOfLoanedBlocks(0) +{ +} + +inline void BumpSpace::init() +{ + m_toSpace = &m_blocks1; + m_fromSpace = &m_blocks2; + + m_totalMemoryAllocated += s_blockSize * s_initialBlockNum; + + if (!addNewBlock()) + CRASH(); +} + +inline bool BumpSpace::contains(void* ptr, BumpBlock*& result) +{ + BumpBlock* block = blockFor(ptr); + result = block; + return !m_toSpaceFilter.ruleOut(reinterpret_cast<Bits>(block)) && m_toSpaceSet.contains(block); +} + +inline void BumpSpace::pin(BumpBlock* block) +{ + block->m_isPinned = true; +} + +inline void BumpSpace::startedCopying() +{ + DoublyLinkedList<HeapBlock>* temp = m_fromSpace; + m_fromSpace = m_toSpace; + m_toSpace = temp; + + m_toSpaceFilter.reset(); + + m_totalMemoryUtilized = 0; + + ASSERT(!m_inCopyingPhase); + ASSERT(!m_numberOfLoanedBlocks); + m_inCopyingPhase = true; +} + +inline void BumpSpace::doneCopying() +{ + { + MutexLocker locker(m_loanedBlocksLock); + while (m_numberOfLoanedBlocks > 0) + m_loanedBlocksCondition.wait(m_loanedBlocksLock); + } + + ASSERT(m_inCopyingPhase); + m_inCopyingPhase = false; + while (!m_fromSpace->isEmpty()) { + BumpBlock* block = static_cast<BumpBlock*>(m_fromSpace->removeHead()); + if (block->m_isPinned) { + block->m_isPinned = false; + m_toSpace->push(block); + continue; + } + + m_toSpaceSet.remove(block); + { + MutexLocker locker(m_heap->m_freeBlockLock); + m_heap->m_freeBlocks.push(block); + m_heap->m_numberOfFreeBlocks++; + } + } + + BumpBlock* curr = static_cast<BumpBlock*>(m_oversizeBlocks.head()); + while (curr) { + BumpBlock* next = static_cast<BumpBlock*>(curr->next()); + if (!curr->m_isPinned) { + m_oversizeBlocks.remove(curr); + m_totalMemoryAllocated -= curr->m_allocation.size(); + m_totalMemoryUtilized -= curr->m_allocation.size() - sizeof(BumpBlock); + curr->m_allocation.deallocate(); + } else + curr->m_isPinned = false; + curr = next; + } + + if (!(m_currentBlock = static_cast<BumpBlock*>(m_toSpace->head()))) + if (!addNewBlock()) + CRASH(); +} + +inline void BumpSpace::doneFillingBlock(BumpBlock* block) +{ + ASSERT(block); + ASSERT(block->m_offset < reinterpret_cast<char*>(block) + s_blockSize); + ASSERT(m_inCopyingPhase); + + if (block->m_offset == block->m_payload) { + recycleBlock(block); + return; + } + + { + MutexLocker locker(m_toSpaceLock); + m_toSpace->push(block); + m_toSpaceSet.add(block); + m_toSpaceFilter.add(reinterpret_cast<Bits>(block)); + } + + { + MutexLocker locker(m_memoryStatsLock); + m_totalMemoryUtilized += static_cast<size_t>(static_cast<char*>(block->m_offset) - block->m_payload); + } + + { + MutexLocker locker(m_loanedBlocksLock); + ASSERT(m_numberOfLoanedBlocks > 0); + m_numberOfLoanedBlocks--; + if (!m_numberOfLoanedBlocks) + m_loanedBlocksCondition.signal(); + } +} + +inline void BumpSpace::recycleBlock(BumpBlock* block) +{ + { + MutexLocker locker(m_heap->m_freeBlockLock); + m_heap->m_freeBlocks.push(block); + m_heap->m_numberOfFreeBlocks++; + } + + { + MutexLocker locker(m_loanedBlocksLock); + ASSERT(m_numberOfLoanedBlocks > 0); + m_numberOfLoanedBlocks--; + if (!m_numberOfLoanedBlocks) + m_loanedBlocksCondition.signal(); + } +} + +inline CheckedBoolean BumpSpace::getFreshBlock(AllocationEffort allocationEffort, BumpBlock** outBlock) +{ + HeapBlock* heapBlock = 0; + BumpBlock* block = 0; + { + MutexLocker locker(m_heap->m_freeBlockLock); + if (!m_heap->m_freeBlocks.isEmpty()) { + heapBlock = m_heap->m_freeBlocks.removeHead(); + m_heap->m_numberOfFreeBlocks--; + } + } + if (heapBlock) + block = new (NotNull, heapBlock) BumpBlock(heapBlock->m_allocation); + else if (allocationEffort == AllocationMustSucceed) { + if (!allocateNewBlock(&block)) { + *outBlock = 0; + ASSERT_NOT_REACHED(); + return false; + } + } else { + ASSERT(allocationEffort == AllocationCanFail); + if (m_heap->waterMark() >= m_heap->highWaterMark() && m_heap->m_isSafeToCollect) + m_heap->collect(Heap::DoNotSweep); + + if (!getFreshBlock(AllocationMustSucceed, &block)) { + *outBlock = 0; + ASSERT_NOT_REACHED(); + return false; + } + } + ASSERT(block); + ASSERT(isPointerAligned(block->m_offset)); + *outBlock = block; + return true; +} + +inline CheckedBoolean BumpSpace::borrowBlock(BumpBlock** outBlock) +{ + BumpBlock* block = 0; + if (!getFreshBlock(AllocationMustSucceed, &block)) { + *outBlock = 0; + return false; + } + + ASSERT(m_inCopyingPhase); + MutexLocker locker(m_loanedBlocksLock); + m_numberOfLoanedBlocks++; + + ASSERT(block->m_offset == block->m_payload); + *outBlock = block; + return true; +} + +inline CheckedBoolean BumpSpace::addNewBlock() +{ + BumpBlock* block = 0; + if (!getFreshBlock(AllocationCanFail, &block)) + return false; + + m_toSpace->push(block); + m_currentBlock = block; + return true; +} + +inline CheckedBoolean BumpSpace::allocateNewBlock(BumpBlock** outBlock) +{ + PageAllocationAligned allocation = PageAllocationAligned::allocate(s_blockSize, s_blockSize, OSAllocator::JSGCHeapPages); + if (!static_cast<bool>(allocation)) { + *outBlock = 0; + return false; + } + + { + MutexLocker locker(m_memoryStatsLock); + m_totalMemoryAllocated += s_blockSize; + } + + *outBlock = new (NotNull, allocation.base()) BumpBlock(allocation); + return true; +} + +inline bool BumpSpace::fitsInBlock(BumpBlock* block, size_t bytes) +{ + return static_cast<char*>(block->m_offset) + bytes < reinterpret_cast<char*>(block) + s_blockSize && static_cast<char*>(block->m_offset) + bytes > block->m_offset; +} + +inline bool BumpSpace::fitsInCurrentBlock(size_t bytes) +{ + return fitsInBlock(m_currentBlock, bytes); +} + +inline CheckedBoolean BumpSpace::tryAllocate(size_t bytes, void** outPtr) +{ + ASSERT(!m_heap->globalData()->isInitializingObject()); + + if (isOversize(bytes) || !fitsInCurrentBlock(bytes)) + return tryAllocateSlowCase(bytes, outPtr); + + *outPtr = allocateFromBlock(m_currentBlock, bytes); + return true; +} + +inline CheckedBoolean BumpSpace::tryAllocateOversize(size_t bytes, void** outPtr) +{ + ASSERT(isOversize(bytes)); + + size_t blockSize = WTF::roundUpToMultipleOf<s_pageSize>(sizeof(BumpBlock) + bytes); + PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, s_pageSize, OSAllocator::JSGCHeapPages); + if (!static_cast<bool>(allocation)) { + *outPtr = 0; + return false; + } + BumpBlock* block = new (NotNull, allocation.base()) BumpBlock(allocation); + m_oversizeBlocks.push(block); + ASSERT(isPointerAligned(block->m_offset)); + + m_oversizeFilter.add(reinterpret_cast<Bits>(block)); + + m_totalMemoryAllocated += blockSize; + m_totalMemoryUtilized += bytes; + + *outPtr = block->m_offset; + return true; +} + +inline void* BumpSpace::allocateFromBlock(BumpBlock* block, size_t bytes) +{ + ASSERT(!isOversize(bytes)); + ASSERT(fitsInBlock(block, bytes)); + ASSERT(isPointerAligned(block->m_offset)); + + void* ptr = block->m_offset; + ASSERT(block->m_offset >= block->m_payload && block->m_offset < reinterpret_cast<char*>(block) + s_blockSize); + block->m_offset = static_cast<void*>((static_cast<char*>(ptr) + bytes)); + ASSERT(block->m_offset >= block->m_payload && block->m_offset < reinterpret_cast<char*>(block) + s_blockSize); + + ASSERT(isPointerAligned(ptr)); + return ptr; +} + +inline CheckedBoolean BumpSpace::tryReallocate(void** ptr, size_t oldSize, size_t newSize) +{ + if (oldSize >= newSize) + return true; + + void* oldPtr = *ptr; + ASSERT(!m_heap->globalData()->isInitializingObject()); + + if (isOversize(oldSize) || isOversize(newSize)) + return tryReallocateOversize(ptr, oldSize, newSize); + + if (static_cast<char*>(oldPtr) + oldSize == m_currentBlock->m_offset && oldPtr > m_currentBlock && oldPtr < reinterpret_cast<char*>(m_currentBlock) + s_blockSize) { + m_currentBlock->m_offset = oldPtr; + if (fitsInCurrentBlock(newSize)) { + m_totalMemoryUtilized += newSize - oldSize; + return allocateFromBlock(m_currentBlock, newSize); + } + } + m_totalMemoryUtilized -= oldSize; + + void* result = 0; + if (!tryAllocate(newSize, &result)) { + *ptr = 0; + return false; + } + memcpy(result, oldPtr, oldSize); + *ptr = result; + return true; +} + +inline CheckedBoolean BumpSpace::tryReallocateOversize(void** ptr, size_t oldSize, size_t newSize) +{ + ASSERT(isOversize(oldSize) || isOversize(newSize)); + ASSERT(newSize > oldSize); + + void* oldPtr = *ptr; + + void* newPtr = 0; + if (!tryAllocateOversize(newSize, &newPtr)) { + *ptr = 0; + return false; + } + memcpy(newPtr, oldPtr, oldSize); + + if (isOversize(oldSize)) { + BumpBlock* oldBlock = oversizeBlockFor(oldPtr); + m_oversizeBlocks.remove(oldBlock); + oldBlock->m_allocation.deallocate(); + m_totalMemoryAllocated -= oldSize + sizeof(BumpBlock); + } + + m_totalMemoryUtilized -= oldSize; + + *ptr = newPtr; + return true; +} + +inline bool BumpSpace::isOversize(size_t bytes) +{ + return bytes > s_maxAllocationSize; +} + +inline bool BumpSpace::isPinned(void* ptr) +{ + return blockFor(ptr)->m_isPinned; +} + +inline BumpBlock* BumpSpace::oversizeBlockFor(void* ptr) +{ + return reinterpret_cast<BumpBlock*>(reinterpret_cast<size_t>(ptr) & s_pageMask); +} + +inline BumpBlock* BumpSpace::blockFor(void* ptr) +{ + return reinterpret_cast<BumpBlock*>(reinterpret_cast<size_t>(ptr) & s_blockMask); +} + +} // namespace JSC + +#endif diff --git a/Source/JavaScriptCore/heap/ConservativeRoots.cpp b/Source/JavaScriptCore/heap/ConservativeRoots.cpp index 05c668c35..a509f06e1 100644 --- a/Source/JavaScriptCore/heap/ConservativeRoots.cpp +++ b/Source/JavaScriptCore/heap/ConservativeRoots.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "ConservativeRoots.h" +#include "BumpSpace.h" +#include "BumpSpaceInlineMethods.h" #include "CodeBlock.h" #include "DFGCodeBlocks.h" #include "JSCell.h" @@ -34,16 +36,12 @@ namespace JSC { -inline bool isPointerAligned(void* p) -{ - return !((intptr_t)(p) & (sizeof(char*) - 1)); -} - -ConservativeRoots::ConservativeRoots(const MarkedBlockSet* blocks) +ConservativeRoots::ConservativeRoots(const MarkedBlockSet* blocks, BumpSpace* bumpSpace) : m_roots(m_inlineRoots) , m_size(0) , m_capacity(inlineCapacity) , m_blocks(blocks) + , m_bumpSpace(bumpSpace) { } @@ -74,6 +72,10 @@ inline void ConservativeRoots::genericAddPointer(void* p, TinyBloomFilter filter { markHook.mark(p); + BumpBlock* block; + if (m_bumpSpace->contains(p, block)) + m_bumpSpace->pin(block); + MarkedBlock* candidate = MarkedBlock::blockFor(p); if (filter.ruleOut(reinterpret_cast<Bits>(candidate))) { ASSERT(!candidate || !m_blocks->set().contains(candidate)); @@ -110,8 +112,8 @@ void ConservativeRoots::genericAddSpan(void* begin, void* end, MarkHook& markHoo void ConservativeRoots::add(void* begin, void* end) { - DummyMarkHook dummyMarkHook; - genericAddSpan(begin, end, dummyMarkHook); + DummyMarkHook hook; + genericAddSpan(begin, end, hook); } void ConservativeRoots::add(void* begin, void* end, DFGCodeBlocks& dfgCodeBlocks) diff --git a/Source/JavaScriptCore/heap/ConservativeRoots.h b/Source/JavaScriptCore/heap/ConservativeRoots.h index 86dfc5886..40b0996d0 100644 --- a/Source/JavaScriptCore/heap/ConservativeRoots.h +++ b/Source/JavaScriptCore/heap/ConservativeRoots.h @@ -38,7 +38,7 @@ class Heap; class ConservativeRoots { public: - ConservativeRoots(const MarkedBlockSet*); + ConservativeRoots(const MarkedBlockSet*, BumpSpace*); ~ConservativeRoots(); void add(void* begin, void* end); @@ -63,6 +63,7 @@ private: size_t m_size; size_t m_capacity; const MarkedBlockSet* m_blocks; + BumpSpace* m_bumpSpace; JSCell* m_inlineRoots[inlineCapacity]; }; diff --git a/Source/JavaScriptCore/heap/HandleHeap.h b/Source/JavaScriptCore/heap/HandleHeap.h index c577791d8..3b9db37a2 100644 --- a/Source/JavaScriptCore/heap/HandleHeap.h +++ b/Source/JavaScriptCore/heap/HandleHeap.h @@ -40,7 +40,7 @@ class JSGlobalData; class JSValue; class SlotVisitor; -class WeakHandleOwner { +class JS_EXPORT_PRIVATE WeakHandleOwner { public: virtual ~WeakHandleOwner(); virtual bool isReachableFromOpaqueRoots(Handle<Unknown>, void* context, SlotVisitor&); @@ -65,7 +65,7 @@ public: void visitWeakHandles(HeapRootVisitor&); void finalizeWeakHandles(); - void writeBarrier(HandleSlot, const JSValue&); + JS_EXPORT_PRIVATE void writeBarrier(HandleSlot, const JSValue&); #if !ASSERT_DISABLED bool hasWeakOwner(HandleSlot, WeakHandleOwner*); @@ -111,7 +111,7 @@ private: static HandleSlot toHandle(Node*); static Node* toNode(HandleSlot); - void grow(); + JS_EXPORT_PRIVATE void grow(); #if ENABLE(GC_VALIDATION) || !ASSERT_DISABLED bool isValidWeakNode(Node*); diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp index 61eba08a4..a2136083a 100644 --- a/Source/JavaScriptCore/heap/Heap.cpp +++ b/Source/JavaScriptCore/heap/Heap.cpp @@ -21,6 +21,8 @@ #include "config.h" #include "Heap.h" +#include "BumpSpace.h" +#include "BumpSpaceInlineMethods.h" #include "CodeBlock.h" #include "ConservativeRoots.h" #include "GCActivityCallback.h" @@ -311,8 +313,11 @@ Heap::Heap(JSGlobalData* globalData, HeapSize heapSize) : m_heapSize(heapSize) , m_minBytesPerCycle(heapSizeForHint(heapSize)) , m_lastFullGCSize(0) + , m_waterMark(0) + , m_highWaterMark(m_minBytesPerCycle) , m_operationInProgress(NoOperation) , m_objectSpace(this) + , m_storageSpace(this) , m_blockFreeingThreadShouldQuit(false) , m_extraCost(0) , m_markListSet(0) @@ -324,12 +329,12 @@ Heap::Heap(JSGlobalData* globalData, HeapSize heapSize) , m_isSafeToCollect(false) , m_globalData(globalData) { - m_objectSpace.setHighWaterMark(m_minBytesPerCycle); (*m_activityCallback)(); m_numberOfFreeBlocks = 0; m_blockFreeingThread = createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree"); ASSERT(m_blockFreeingThread); + m_storageSpace.init(); } Heap::~Heap() @@ -433,7 +438,7 @@ void Heap::blockFreeingThreadMain() if (m_numberOfFreeBlocks <= desiredNumberOfFreeBlocks) block = 0; else { - block = m_freeBlocks.removeHead(); + block = static_cast<MarkedBlock*>(m_freeBlocks.removeHead()); ASSERT(block); m_numberOfFreeBlocks--; } @@ -460,7 +465,7 @@ void Heap::reportExtraMemoryCostSlowCase(size_t cost) // if a large value survives one garbage collection, there is not much point to // collecting more frequently as long as it stays alive. - if (m_extraCost > maxExtraCost && m_extraCost > m_objectSpace.highWaterMark() / 2) + if (m_extraCost > maxExtraCost && m_extraCost > highWaterMark() / 2) collectAllGarbage(); m_extraCost += cost; } @@ -509,7 +514,7 @@ void Heap::popTempSortVector(Vector<ValueStringPair>* tempVector) ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last()); m_tempSortingVectors.removeLast(); } - + void Heap::markTempSortVectors(HeapRootVisitor& heapRootVisitor) { typedef Vector<Vector<ValueStringPair>* > VectorOfValueStringVectors; @@ -547,7 +552,7 @@ void Heap::getConservativeRegisterRoots(HashSet<JSCell*>& roots) if (m_operationInProgress != NoOperation) CRASH(); m_operationInProgress = Collection; - ConservativeRoots registerFileRoots(&m_objectSpace.blocks()); + ConservativeRoots registerFileRoots(&m_objectSpace.blocks(), &m_storageSpace); registerFile().gatherConservativeRoots(registerFileRoots); size_t registerFileRootCount = registerFileRoots.size(); JSCell** registerRoots = registerFileRoots.roots(); @@ -573,13 +578,13 @@ void Heap::markRoots(bool fullGC) // We gather conservative roots before clearing mark bits because conservative // gathering uses the mark bits to determine whether a reference is valid. - ConservativeRoots machineThreadRoots(&m_objectSpace.blocks()); + ConservativeRoots machineThreadRoots(&m_objectSpace.blocks(), &m_storageSpace); { GCPHASE(GatherConservativeRoots); m_machineThreads.gatherConservativeRoots(machineThreadRoots, &dummy); } - ConservativeRoots registerFileRoots(&m_objectSpace.blocks()); + ConservativeRoots registerFileRoots(&m_objectSpace.blocks(), &m_storageSpace); m_dfgCodeBlocks.clearMarks(); { GCPHASE(GatherRegisterFileRoots); @@ -597,6 +602,7 @@ void Heap::markRoots(bool fullGC) clearMarks(); } + m_storageSpace.startedCopying(); SlotVisitor& visitor = m_slotVisitor; HeapRootVisitor heapRootVisitor(visitor); @@ -700,8 +706,10 @@ void Heap::markRoots(bool fullGC) } GCCOUNTER(VisitedValueCount, visitor.visitCount()); + visitor.doneCopying(); visitor.reset(); m_sharedData.reset(); + m_storageSpace.doneCopying(); m_operationInProgress = NoOperation; } @@ -822,11 +830,11 @@ void Heap::collect(SweepToggle sweepToggle) // water mark to be proportional to the current size of the heap. The exact // proportion is a bit arbitrary. A 2X multiplier gives a 1:1 (heap size : // new bytes allocated) proportion, and seems to work well in benchmarks. - size_t newSize = size(); + size_t newSize = size() + m_storageSpace.totalMemoryUtilized(); size_t proportionalBytes = 2 * newSize; if (fullGC) { m_lastFullGCSize = newSize; - m_objectSpace.setHighWaterMark(max(proportionalBytes, m_minBytesPerCycle)); + setHighWaterMark(max(proportionalBytes, m_minBytesPerCycle)); } JAVASCRIPTCORE_GC_END(); @@ -887,7 +895,7 @@ void Heap::releaseFreeBlocks() if (!m_numberOfFreeBlocks) block = 0; else { - block = m_freeBlocks.removeHead(); + block = static_cast<MarkedBlock*>(m_freeBlocks.removeHead()); ASSERT(block); m_numberOfFreeBlocks--; } diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h index 1b228253b..40a8376f0 100644 --- a/Source/JavaScriptCore/heap/Heap.h +++ b/Source/JavaScriptCore/heap/Heap.h @@ -22,7 +22,6 @@ #ifndef Heap_h #define Heap_h -#include "AllocationSpace.h" #include "DFGCodeBlocks.h" #include "HandleHeap.h" #include "HandleStack.h" @@ -31,12 +30,16 @@ #include "MarkedSpace.h" #include "SlotVisitor.h" #include "WriteBarrierSupport.h" +#include <wtf/DoublyLinkedList.h> #include <wtf/Forward.h> #include <wtf/HashCountedSet.h> #include <wtf/HashSet.h> +#define COLLECT_ON_EVERY_ALLOCATION 0 + namespace JSC { + class BumpSpace; class CodeBlock; class GCActivityCallback; class GlobalCodeBlock; @@ -57,7 +60,7 @@ namespace JSC { typedef HashCountedSet<const char*> TypeCountSet; enum OperationInProgress { NoOperation, Allocation, Collection }; - + // Heap size hint. enum HeapSize { SmallHeap, LargeHeap }; @@ -65,6 +68,7 @@ namespace JSC { WTF_MAKE_NONCOPYABLE(Heap); public: friend class JIT; + friend class MarkStackThreadSharedData; static Heap* heap(JSValue); // 0 for immediate values static Heap* heap(JSCell*); @@ -78,42 +82,44 @@ namespace JSC { Heap(JSGlobalData*, HeapSize); ~Heap(); - void destroy(); // JSGlobalData must call destroy() before ~Heap(). + JS_EXPORT_PRIVATE void destroy(); // JSGlobalData must call destroy() before ~Heap(). JSGlobalData* globalData() const { return m_globalData; } - AllocationSpace& objectSpace() { return m_objectSpace; } + MarkedSpace& objectSpace() { return m_objectSpace; } MachineThreads& machineThreads() { return m_machineThreads; } - GCActivityCallback* activityCallback(); - void setActivityCallback(PassOwnPtr<GCActivityCallback>); + JS_EXPORT_PRIVATE GCActivityCallback* activityCallback(); + JS_EXPORT_PRIVATE void setActivityCallback(PassOwnPtr<GCActivityCallback>); // true if an allocation or collection is in progress inline bool isBusy(); MarkedSpace::SizeClass& sizeClassForObject(size_t bytes) { return m_objectSpace.sizeClassFor(bytes); } void* allocate(size_t); + CheckedBoolean tryAllocateStorage(size_t, void**); + CheckedBoolean tryReallocateStorage(void**, size_t, size_t); typedef void (*Finalizer)(JSCell*); - void addFinalizer(JSCell*, Finalizer); + JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer); void notifyIsSafeToCollect() { m_isSafeToCollect = true; } - void collectAllGarbage(); + JS_EXPORT_PRIVATE void collectAllGarbage(); void reportExtraMemoryCost(size_t cost); - void protect(JSValue); - bool unprotect(JSValue); // True when the protect count drops to 0. + JS_EXPORT_PRIVATE void protect(JSValue); + JS_EXPORT_PRIVATE bool unprotect(JSValue); // True when the protect count drops to 0. void jettisonDFGCodeBlock(PassOwnPtr<CodeBlock>); - size_t size(); - size_t capacity(); - size_t objectCount(); - size_t globalObjectCount(); - size_t protectedObjectCount(); - size_t protectedGlobalObjectCount(); - PassOwnPtr<TypeCountSet> protectedObjectTypeCounts(); - PassOwnPtr<TypeCountSet> objectTypeCounts(); + JS_EXPORT_PRIVATE size_t size(); + JS_EXPORT_PRIVATE size_t capacity(); + JS_EXPORT_PRIVATE size_t objectCount(); + JS_EXPORT_PRIVATE size_t globalObjectCount(); + JS_EXPORT_PRIVATE size_t protectedObjectCount(); + JS_EXPORT_PRIVATE size_t protectedGlobalObjectCount(); + JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> protectedObjectTypeCounts(); + JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> objectTypeCounts(); void pushTempSortVector(Vector<ValueStringPair>*); void popTempSortVector(Vector<ValueStringPair>*); @@ -129,11 +135,16 @@ namespace JSC { void getConservativeRegisterRoots(HashSet<JSCell*>& roots); private: + friend class MarkedSpace; friend class MarkedBlock; - friend class AllocationSpace; + friend class BumpSpace; friend class SlotVisitor; friend class CodeBlock; + size_t waterMark(); + size_t highWaterMark(); + void setHighWaterMark(size_t); + static const size_t minExtraCost = 256; static const size_t maxExtraCost = 1024 * 1024; @@ -141,8 +152,8 @@ namespace JSC { virtual void finalize(Handle<Unknown>, void* context); }; - bool isValidAllocation(size_t); - void reportExtraMemoryCostSlowCase(size_t); + JS_EXPORT_PRIVATE bool isValidAllocation(size_t); + JS_EXPORT_PRIVATE void reportExtraMemoryCostSlowCase(size_t); // Call this function before any operation that needs to know which cells // in the heap are live. (For example, call this function before @@ -175,11 +186,14 @@ namespace JSC { const HeapSize m_heapSize; const size_t m_minBytesPerCycle; size_t m_lastFullGCSize; + size_t m_waterMark; + size_t m_highWaterMark; OperationInProgress m_operationInProgress; - AllocationSpace m_objectSpace; + MarkedSpace m_objectSpace; + BumpSpace m_storageSpace; - DoublyLinkedList<MarkedBlock> m_freeBlocks; + DoublyLinkedList<HeapBlock> m_freeBlocks; size_t m_numberOfFreeBlocks; ThreadIdentifier m_blockFreeingThread; @@ -246,6 +260,21 @@ namespace JSC { MarkedBlock::blockFor(cell)->setMarked(cell); } + inline size_t Heap::waterMark() + { + return m_objectSpace.waterMark() + m_storageSpace.totalMemoryUtilized(); + } + + inline size_t Heap::highWaterMark() + { + return m_highWaterMark; + } + + inline void Heap::setHighWaterMark(size_t newHighWaterMark) + { + m_highWaterMark = newHighWaterMark; + } + #if ENABLE(GGC) inline uint8_t* Heap::addressOfCardFor(JSCell* cell) { @@ -308,6 +337,16 @@ namespace JSC { ASSERT(isValidAllocation(bytes)); return m_objectSpace.allocate(bytes); } + + inline CheckedBoolean Heap::tryAllocateStorage(size_t bytes, void** outPtr) + { + return m_storageSpace.tryAllocate(bytes, outPtr); + } + + inline CheckedBoolean Heap::tryReallocateStorage(void** ptr, size_t oldSize, size_t newSize) + { + return m_storageSpace.tryReallocate(ptr, oldSize, newSize); + } } // namespace JSC diff --git a/Source/JavaScriptCore/heap/HeapBlock.h b/Source/JavaScriptCore/heap/HeapBlock.h new file mode 100644 index 000000000..b0ecb2059 --- /dev/null +++ b/Source/JavaScriptCore/heap/HeapBlock.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 HeapBlock_h +#define HeapBlock_h + +#include <wtf/DoublyLinkedList.h> +#include <wtf/PageAllocationAligned.h> + +namespace JSC { + +enum AllocationEffort { AllocationCanFail, AllocationMustSucceed }; + +class HeapBlock : public DoublyLinkedListNode<HeapBlock> { +public: + HeapBlock(PageAllocationAligned& allocation) + : DoublyLinkedListNode<HeapBlock>() + , m_prev(0) + , m_next(0) + , m_allocation(allocation) + { + ASSERT(allocation); + } + + HeapBlock* m_prev; + HeapBlock* m_next; + PageAllocationAligned m_allocation; +}; + +} // namespace JSC + +#endif diff --git a/Source/JavaScriptCore/heap/MachineStackMarker.cpp b/Source/JavaScriptCore/heap/MachineStackMarker.cpp index f62ee066f..fd828d5de 100644 --- a/Source/JavaScriptCore/heap/MachineStackMarker.cpp +++ b/Source/JavaScriptCore/heap/MachineStackMarker.cpp @@ -193,7 +193,7 @@ void MachineThreads::addCurrentThread() return; pthread_setspecific(m_threadSpecific, this); - Thread* thread = new Thread(getCurrentPlatformThread(), m_heap->globalData()->stack().origin()); + Thread* thread = new Thread(getCurrentPlatformThread(), wtfThreadData().stack().origin()); MutexLocker lock(m_registeredThreadsMutex); @@ -257,7 +257,7 @@ void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoot conservativeRoots.add(registersBegin, registersEnd); void* stackBegin = stackCurrent; - void* stackEnd = m_heap->globalData()->stack().origin(); + void* stackEnd = wtfThreadData().stack().origin(); swapIfBackwards(stackBegin, stackEnd); conservativeRoots.add(stackBegin, stackEnd); } diff --git a/Source/JavaScriptCore/heap/MachineStackMarker.h b/Source/JavaScriptCore/heap/MachineStackMarker.h index 69c4537bd..0f5a4c3aa 100644 --- a/Source/JavaScriptCore/heap/MachineStackMarker.h +++ b/Source/JavaScriptCore/heap/MachineStackMarker.h @@ -40,7 +40,7 @@ namespace JSC { void gatherConservativeRoots(ConservativeRoots&, void* stackCurrent); void makeUsableFromMultipleThreads(); - void addCurrentThread(); // Only needs to be called by clients that can use the same heap from multiple threads. + JS_EXPORT_PRIVATE void addCurrentThread(); // Only needs to be called by clients that can use the same heap from multiple threads. private: void gatherFromCurrentThread(ConservativeRoots&, void* stackCurrent); diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp index 02cf328d4..9a3092396 100644 --- a/Source/JavaScriptCore/heap/MarkStack.cpp +++ b/Source/JavaScriptCore/heap/MarkStack.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "MarkStack.h" +#include "BumpSpace.h" +#include "BumpSpaceInlineMethods.h" #include "ConservativeRoots.h" #include "Heap.h" #include "Options.h" @@ -233,6 +235,7 @@ void* MarkStackThreadSharedData::markingThreadStartFunc(void* shared) MarkStackThreadSharedData::MarkStackThreadSharedData(JSGlobalData* globalData) : m_globalData(globalData) + , m_bumpSpace(&globalData->heap.m_storageSpace) , m_sharedMarkStack(m_segmentAllocator) , m_numberOfActiveParallelMarkers(0) , m_parallelMarkersShouldExit(false) @@ -337,7 +340,7 @@ void SlotVisitor::donateSlow() void SlotVisitor::drain() { ASSERT(m_isInParallelMode); - + #if ENABLE(PARALLEL_GC) if (Options::numberOfGCMarkers > 1) { while (!m_stack.isEmpty()) { @@ -398,8 +401,11 @@ void SlotVisitor::drainFromShared(SharedDrainMode sharedDrainMode) // for us to do. while (true) { // Did we reach termination? - if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty()) + if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty()) { + // Let any sleeping slaves know it's time for them to give their private BumpBlocks back + m_shared.m_markingCondition.broadcast(); return; + } // Is there work to be done? if (!m_shared.m_sharedMarkStack.isEmpty()) @@ -415,14 +421,19 @@ void SlotVisitor::drainFromShared(SharedDrainMode sharedDrainMode) if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty()) m_shared.m_markingCondition.broadcast(); - while (m_shared.m_sharedMarkStack.isEmpty() && !m_shared.m_parallelMarkersShouldExit) + while (m_shared.m_sharedMarkStack.isEmpty() && !m_shared.m_parallelMarkersShouldExit) { + if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty()) + doneCopying(); m_shared.m_markingCondition.wait(m_shared.m_markingLock); + } // Is the VM exiting? If so, exit this thread. - if (m_shared.m_parallelMarkersShouldExit) + if (m_shared.m_parallelMarkersShouldExit) { + doneCopying(); return; + } } - + m_stack.stealSomeCellsFrom(m_shared.m_sharedMarkStack); m_shared.m_numberOfActiveParallelMarkers++; } @@ -445,6 +456,79 @@ void MarkStack::mergeOpaqueRoots() m_opaqueRoots.clear(); } +void SlotVisitor::startCopying() +{ + ASSERT(!m_copyBlock); + if (!m_shared.m_bumpSpace->borrowBlock(&m_copyBlock)) + CRASH(); +} + +void* SlotVisitor::allocateNewSpace(void* ptr, size_t bytes) +{ + if (BumpSpace::isOversize(bytes)) { + m_shared.m_bumpSpace->pin(BumpSpace::oversizeBlockFor(ptr)); + return 0; + } + + if (m_shared.m_bumpSpace->isPinned(ptr)) + return 0; + + // The only time it's possible to have a null copy block is if we have just started copying. + if (!m_copyBlock) + startCopying(); + + if (!BumpSpace::fitsInBlock(m_copyBlock, bytes)) { + // We don't need to lock across these two calls because the master thread won't + // call doneCopying() because this thread is considered active. + m_shared.m_bumpSpace->doneFillingBlock(m_copyBlock); + if (!m_shared.m_bumpSpace->borrowBlock(&m_copyBlock)) + CRASH(); + } + return BumpSpace::allocateFromBlock(m_copyBlock, bytes); +} + +void SlotVisitor::copy(void** ptr, size_t bytes) +{ + void* newPtr = 0; + if (!(newPtr = allocateNewSpace(*ptr, bytes))) + return; + + memcpy(newPtr, *ptr, bytes); + *ptr = newPtr; +} + +void SlotVisitor::copyAndAppend(void** ptr, size_t bytes, JSValue* values, unsigned length) +{ + void* oldPtr = *ptr; + void* newPtr = allocateNewSpace(oldPtr, bytes); + if (newPtr) { + size_t jsValuesOffset = static_cast<size_t>(reinterpret_cast<char*>(values) - static_cast<char*>(oldPtr)); + + JSValue* newValues = reinterpret_cast<JSValue*>(static_cast<char*>(newPtr) + jsValuesOffset); + for (unsigned i = 0; i < length; i++) { + JSValue& value = values[i]; + newValues[i] = value; + if (!value) + continue; + internalAppend(value); + } + + memcpy(newPtr, oldPtr, jsValuesOffset); + *ptr = newPtr; + } else + append(values, length); +} + +void SlotVisitor::doneCopying() +{ + if (!m_copyBlock) + return; + + m_shared.m_bumpSpace->doneFillingBlock(m_copyBlock); + + m_copyBlock = 0; +} + void SlotVisitor::harvestWeakReferences() { for (WeakReferenceHarvester* current = m_shared.m_weakReferenceHarvesters.head(); current; current = current->next()) diff --git a/Source/JavaScriptCore/heap/MarkStack.h b/Source/JavaScriptCore/heap/MarkStack.h index 1478011d9..6923cdd8a 100644 --- a/Source/JavaScriptCore/heap/MarkStack.h +++ b/Source/JavaScriptCore/heap/MarkStack.h @@ -26,6 +26,7 @@ #ifndef MarkStack_h #define MarkStack_h +#include "BumpSpace.h" #include "HandleTypes.h" #include "Options.h" #include "JSValue.h" @@ -111,7 +112,7 @@ namespace JSC { private: MarkStackSegment* m_topSegment; - void expand(); + JS_EXPORT_PRIVATE void expand(); MarkStackSegmentAllocator& m_allocator; @@ -181,6 +182,7 @@ namespace JSC { #endif JSGlobalData* m_globalData; + BumpSpace* m_bumpSpace; MarkStackSegmentAllocator m_segmentAllocator; @@ -241,7 +243,7 @@ namespace JSC { } protected: - static void validate(JSCell*); + JS_EXPORT_PRIVATE static void validate(JSCell*); void append(JSValue*); void append(JSValue*, size_t count); @@ -250,7 +252,7 @@ namespace JSC { void internalAppend(JSCell*); void internalAppend(JSValue); - void mergeOpaqueRoots(); + JS_EXPORT_PRIVATE void mergeOpaqueRoots(); void mergeOpaqueRootsIfNecessary() { diff --git a/Source/JavaScriptCore/heap/MarkedBlock.cpp b/Source/JavaScriptCore/heap/MarkedBlock.cpp index 771c9c082..715f25d92 100644 --- a/Source/JavaScriptCore/heap/MarkedBlock.cpp +++ b/Source/JavaScriptCore/heap/MarkedBlock.cpp @@ -40,9 +40,9 @@ MarkedBlock* MarkedBlock::create(Heap* heap, size_t cellSize) return new (NotNull, allocation.base()) MarkedBlock(allocation, heap, cellSize); } -MarkedBlock* MarkedBlock::recycle(MarkedBlock* block, size_t cellSize) +MarkedBlock* MarkedBlock::recycle(MarkedBlock* block, Heap* heap, size_t cellSize) { - return new (NotNull, block) MarkedBlock(block->m_allocation, block->m_heap, cellSize); + return new (NotNull, block) MarkedBlock(block->m_allocation, heap, cellSize); } void MarkedBlock::destroy(MarkedBlock* block) @@ -50,13 +50,14 @@ void MarkedBlock::destroy(MarkedBlock* block) block->m_allocation.deallocate(); } -MarkedBlock::MarkedBlock(const PageAllocationAligned& allocation, Heap* heap, size_t cellSize) - : m_atomsPerCell((cellSize + atomSize - 1) / atomSize) +MarkedBlock::MarkedBlock(PageAllocationAligned& allocation, Heap* heap, size_t cellSize) + : HeapBlock(allocation) + , m_atomsPerCell((cellSize + atomSize - 1) / atomSize) , m_endAtom(atomsPerBlock - m_atomsPerCell + 1) , m_state(New) // All cells start out unmarked. - , m_allocation(allocation) , m_heap(heap) { + ASSERT(heap); HEAP_LOG_BLOCK_STATE_TRANSITION(this); } diff --git a/Source/JavaScriptCore/heap/MarkedBlock.h b/Source/JavaScriptCore/heap/MarkedBlock.h index 8c665dd5b..00eb54b1f 100644 --- a/Source/JavaScriptCore/heap/MarkedBlock.h +++ b/Source/JavaScriptCore/heap/MarkedBlock.h @@ -23,6 +23,7 @@ #define MarkedBlock_h #include "CardSet.h" +#include "HeapBlock.h" #include <wtf/Bitmap.h> #include <wtf/DoublyLinkedList.h> @@ -50,7 +51,6 @@ namespace JSC { typedef uintptr_t Bits; - static const size_t KB = 1024; static const size_t MB = 1024 * 1024; bool isZapped(const JSCell*); @@ -63,14 +63,14 @@ namespace JSC { // size is equal to the difference between the cell size and the object // size. - class MarkedBlock : public DoublyLinkedListNode<MarkedBlock> { + class MarkedBlock : public HeapBlock { friend class WTF::DoublyLinkedListNode<MarkedBlock>; public: // Ensure natural alignment for native types whilst recognizing that the smallest // object the heap will commonly allocate is four words. static const size_t atomSize = 4 * sizeof(void*); static const size_t atomShift = 5; - static const size_t blockSize = 16 * KB; + static const size_t blockSize = 64 * KB; static const size_t blockMask = ~(blockSize - 1); // blockSize must be a power of two. static const size_t atomsPerBlock = blockSize / atomSize; // ~0.4% overhead @@ -90,7 +90,7 @@ namespace JSC { }; static MarkedBlock* create(Heap*, size_t cellSize); - static MarkedBlock* recycle(MarkedBlock*, size_t cellSize); + static MarkedBlock* recycle(MarkedBlock*, Heap*, size_t cellSize); static void destroy(MarkedBlock*); static bool isAtomAligned(const void*); @@ -162,7 +162,7 @@ namespace JSC { typedef char Atom[atomSize]; - MarkedBlock(const PageAllocationAligned&, Heap*, size_t cellSize); + MarkedBlock(PageAllocationAligned&, Heap*, size_t cellSize); Atom* atoms(); size_t atomNumber(const void*); void callDestructor(JSCell*); @@ -180,10 +180,7 @@ namespace JSC { WTF::Bitmap<atomsPerBlock, WTF::BitmapNotAtomic> m_marks; #endif BlockState m_state; - PageAllocationAligned m_allocation; Heap* m_heap; - MarkedBlock* m_prev; - MarkedBlock* m_next; }; inline size_t MarkedBlock::firstAtom() diff --git a/Source/JavaScriptCore/heap/MarkedSpace.cpp b/Source/JavaScriptCore/heap/MarkedSpace.cpp index acbd8acac..fcca188e4 100644 --- a/Source/JavaScriptCore/heap/MarkedSpace.cpp +++ b/Source/JavaScriptCore/heap/MarkedSpace.cpp @@ -33,7 +33,6 @@ class Structure; MarkedSpace::MarkedSpace(Heap* heap) : m_waterMark(0) , m_nurseryWaterMark(0) - , m_highWaterMark(0) , m_heap(heap) { for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) @@ -82,4 +81,192 @@ void MarkedSpace::canonicalizeCellLivenessData() sizeClassFor(cellSize).zapFreeList(); } +inline void* MarkedSpace::tryAllocateHelper(MarkedSpace::SizeClass& sizeClass) +{ + MarkedBlock::FreeCell* firstFreeCell = sizeClass.firstFreeCell; + if (!firstFreeCell) { + for (MarkedBlock*& block = sizeClass.currentBlock; block; block = static_cast<MarkedBlock*>(block->next())) { + firstFreeCell = block->sweep(MarkedBlock::SweepToFreeList); + if (firstFreeCell) + break; + m_nurseryWaterMark += block->capacity() - block->size(); + m_waterMark += block->capacity(); + block->didConsumeFreeList(); + } + + if (!firstFreeCell) + return 0; + } + + ASSERT(firstFreeCell); + sizeClass.firstFreeCell = firstFreeCell->next; + return firstFreeCell; +} + +inline void* MarkedSpace::tryAllocate(MarkedSpace::SizeClass& sizeClass) +{ + m_heap->m_operationInProgress = Allocation; + void* result = tryAllocateHelper(sizeClass); + m_heap->m_operationInProgress = NoOperation; + return result; +} + +void* MarkedSpace::allocateSlowCase(MarkedSpace::SizeClass& sizeClass) +{ +#if COLLECT_ON_EVERY_ALLOCATION + m_heap->collectAllGarbage(); + ASSERT(m_heap->m_operationInProgress == NoOperation); +#endif + + void* result = tryAllocate(sizeClass); + + if (LIKELY(result != 0)) + return result; + + AllocationEffort allocationEffort; + + if (( +#if ENABLE(GGC) + nurseryWaterMark() < m_heap->m_minBytesPerCycle +#else + m_heap->waterMark() < m_heap->highWaterMark() +#endif + ) || !m_heap->m_isSafeToCollect) + allocationEffort = AllocationMustSucceed; + else + allocationEffort = AllocationCanFail; + + MarkedBlock* block = allocateBlock(sizeClass.cellSize, allocationEffort); + if (block) { + addBlock(sizeClass, block); + void* result = tryAllocate(sizeClass); + ASSERT(result); + return result; + } + + m_heap->collect(Heap::DoNotSweep); + + result = tryAllocate(sizeClass); + + if (result) + return result; + + ASSERT(m_heap->waterMark() < m_heap->highWaterMark()); + + addBlock(sizeClass, allocateBlock(sizeClass.cellSize, AllocationMustSucceed)); + + result = tryAllocate(sizeClass); + ASSERT(result); + return result; +} + +MarkedBlock* MarkedSpace::allocateBlock(size_t cellSize, AllocationEffort allocationEffort) +{ + MarkedBlock* block; + + { + MutexLocker locker(m_heap->m_freeBlockLock); + if (m_heap->m_numberOfFreeBlocks) { + block = static_cast<MarkedBlock*>(m_heap->m_freeBlocks.removeHead()); + ASSERT(block); + m_heap->m_numberOfFreeBlocks--; + } else + block = 0; + } + if (block) + block = MarkedBlock::recycle(block, m_heap, cellSize); + else if (allocationEffort == AllocationCanFail) + return 0; + else + block = MarkedBlock::create(m_heap, cellSize); + + m_blocks.add(block); + + return block; +} + +void MarkedSpace::freeBlocks(MarkedBlock* head) +{ + MarkedBlock* next; + for (MarkedBlock* block = head; block; block = next) { + next = static_cast<MarkedBlock*>(block->next()); + + m_blocks.remove(block); + block->sweep(); + MutexLocker locker(m_heap->m_freeBlockLock); + m_heap->m_freeBlocks.append(block); + m_heap->m_numberOfFreeBlocks++; + } +} + +class TakeIfUnmarked { +public: + typedef MarkedBlock* ReturnType; + + TakeIfUnmarked(MarkedSpace*); + void operator()(MarkedBlock*); + ReturnType returnValue(); + +private: + MarkedSpace* m_markedSpace; + DoublyLinkedList<MarkedBlock> m_empties; +}; + +inline TakeIfUnmarked::TakeIfUnmarked(MarkedSpace* newSpace) + : m_markedSpace(newSpace) +{ +} + +inline void TakeIfUnmarked::operator()(MarkedBlock* block) +{ + if (!block->markCountIsZero()) + return; + + m_markedSpace->removeBlock(block); + m_empties.append(block); +} + +inline TakeIfUnmarked::ReturnType TakeIfUnmarked::returnValue() +{ + return m_empties.head(); +} + +void MarkedSpace::shrink() +{ + // We record a temporary list of empties to avoid modifying m_blocks while iterating it. + TakeIfUnmarked takeIfUnmarked(this); + freeBlocks(forEachBlock(takeIfUnmarked)); +} + +#if ENABLE(GGC) +class GatherDirtyCells { + WTF_MAKE_NONCOPYABLE(GatherDirtyCells); +public: + typedef void* ReturnType; + + explicit GatherDirtyCells(MarkedBlock::DirtyCellVector*); + void operator()(MarkedBlock*); + ReturnType returnValue() { return 0; } + +private: + MarkedBlock::DirtyCellVector* m_dirtyCells; +}; + +inline GatherDirtyCells::GatherDirtyCells(MarkedBlock::DirtyCellVector* dirtyCells) + : m_dirtyCells(dirtyCells) +{ +} + +inline void GatherDirtyCells::operator()(MarkedBlock* block) +{ + block->gatherDirtyCells(*m_dirtyCells); +} + +void MarkedSpace::gatherDirtyCells(MarkedBlock::DirtyCellVector& dirtyCells) +{ + GatherDirtyCells gatherDirtyCells(&dirtyCells); + forEachBlock(gatherDirtyCells); +} +#endif + } // namespace JSC diff --git a/Source/JavaScriptCore/heap/MarkedSpace.h b/Source/JavaScriptCore/heap/MarkedSpace.h index 751fe2fee..f7d96c774 100644 --- a/Source/JavaScriptCore/heap/MarkedSpace.h +++ b/Source/JavaScriptCore/heap/MarkedSpace.h @@ -24,6 +24,7 @@ #include "MachineStackMarker.h" #include "MarkedBlock.h" +#include "MarkedBlockSet.h" #include "PageAllocationAligned.h" #include <wtf/Bitmap.h> #include <wtf/DoublyLinkedList.h> @@ -54,31 +55,43 @@ public: MarkedBlock::FreeCell* firstFreeCell; MarkedBlock* currentBlock; - DoublyLinkedList<MarkedBlock> blockList; + DoublyLinkedList<HeapBlock> blockList; size_t cellSize; }; MarkedSpace(Heap*); SizeClass& sizeClassFor(size_t); + void* allocate(size_t); void* allocate(SizeClass&); void resetAllocator(); void addBlock(SizeClass&, MarkedBlock*); void removeBlock(MarkedBlock*); + MarkedBlockSet& blocks() { return m_blocks; } void canonicalizeCellLivenessData(); size_t waterMark(); - size_t highWaterMark(); size_t nurseryWaterMark(); - void setHighWaterMark(size_t); - template<typename Functor> typename Functor::ReturnType forEachBlock(Functor&); // Safe to remove the current item while iterating. + typedef HashSet<MarkedBlock*>::iterator BlockIterator; + + template<typename Functor> typename Functor::ReturnType forEachCell(Functor&); + template<typename Functor> typename Functor::ReturnType forEachCell(); + template<typename Functor> typename Functor::ReturnType forEachBlock(Functor&); template<typename Functor> typename Functor::ReturnType forEachBlock(); + + void shrink(); + void freeBlocks(MarkedBlock* head); private: + JS_EXPORT_PRIVATE void* allocateSlowCase(SizeClass&); + void* tryAllocateHelper(MarkedSpace::SizeClass&); + void* tryAllocate(MarkedSpace::SizeClass&); + MarkedBlock* allocateBlock(size_t, AllocationEffort); + // [ 32... 256 ] static const size_t preciseStep = MarkedBlock::atomSize; static const size_t preciseCutoff = 256; @@ -93,8 +106,8 @@ private: FixedArray<SizeClass, impreciseCount> m_impreciseSizeClasses; size_t m_waterMark; size_t m_nurseryWaterMark; - size_t m_highWaterMark; Heap* m_heap; + MarkedBlockSet m_blocks; }; inline size_t MarkedSpace::waterMark() @@ -102,19 +115,25 @@ inline size_t MarkedSpace::waterMark() return m_waterMark; } -inline size_t MarkedSpace::highWaterMark() +inline size_t MarkedSpace::nurseryWaterMark() { - return m_highWaterMark; + return m_nurseryWaterMark; } -inline size_t MarkedSpace::nurseryWaterMark() +template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachCell(Functor& functor) { - return m_nurseryWaterMark; + canonicalizeCellLivenessData(); + + BlockIterator end = m_blocks.set().end(); + for (BlockIterator it = m_blocks.set().begin(); it != end; ++it) + (*it)->forEachCell(functor); + return functor.returnValue(); } -inline void MarkedSpace::setHighWaterMark(size_t highWaterMark) +template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachCell() { - m_highWaterMark = highWaterMark; + Functor functor; + return forEachCell(functor); } inline MarkedSpace::SizeClass& MarkedSpace::sizeClassFor(size_t bytes) @@ -125,25 +144,19 @@ inline MarkedSpace::SizeClass& MarkedSpace::sizeClassFor(size_t bytes) return m_impreciseSizeClasses[(bytes - 1) / impreciseStep]; } +inline void* MarkedSpace::allocate(size_t bytes) +{ + SizeClass& sizeClass = sizeClassFor(bytes); + return allocate(sizeClass); +} + inline void* MarkedSpace::allocate(SizeClass& sizeClass) { + // This is a light-weight fast path to cover the most common case. MarkedBlock::FreeCell* firstFreeCell = sizeClass.firstFreeCell; - if (!firstFreeCell) { - for (MarkedBlock*& block = sizeClass.currentBlock; block; block = block->next()) { - firstFreeCell = block->sweep(MarkedBlock::SweepToFreeList); - if (firstFreeCell) - break; - m_nurseryWaterMark += block->capacity() - block->size(); - m_waterMark += block->capacity(); - block->didConsumeFreeList(); - } - - if (!firstFreeCell) - return 0; - } - - ASSERT(firstFreeCell); - + if (UNLIKELY(!firstFreeCell)) + return allocateSlowCase(sizeClass); + sizeClass.firstFreeCell = firstFreeCell->next; return firstFreeCell; } @@ -152,19 +165,19 @@ template <typename Functor> inline typename Functor::ReturnType MarkedSpace::for { for (size_t i = 0; i < preciseCount; ++i) { SizeClass& sizeClass = m_preciseSizeClasses[i]; - MarkedBlock* next; - for (MarkedBlock* block = sizeClass.blockList.head(); block; block = next) { + HeapBlock* next; + for (HeapBlock* block = sizeClass.blockList.head(); block; block = next) { next = block->next(); - functor(block); + functor(static_cast<MarkedBlock*>(block)); } } for (size_t i = 0; i < impreciseCount; ++i) { SizeClass& sizeClass = m_impreciseSizeClasses[i]; - MarkedBlock* next; - for (MarkedBlock* block = sizeClass.blockList.head(); block; block = next) { + HeapBlock* next; + for (HeapBlock* block = sizeClass.blockList.head(); block; block = next) { next = block->next(); - functor(block); + functor(static_cast<MarkedBlock*>(block)); } } @@ -186,7 +199,7 @@ inline MarkedSpace::SizeClass::SizeClass() inline void MarkedSpace::SizeClass::resetAllocator() { - currentBlock = blockList.head(); + currentBlock = static_cast<MarkedBlock*>(blockList.head()); } inline void MarkedSpace::SizeClass::zapFreeList() diff --git a/Source/JavaScriptCore/heap/SlotVisitor.h b/Source/JavaScriptCore/heap/SlotVisitor.h index 142d8ca49..e49a9a637 100644 --- a/Source/JavaScriptCore/heap/SlotVisitor.h +++ b/Source/JavaScriptCore/heap/SlotVisitor.h @@ -26,6 +26,7 @@ #ifndef SlotVisitor_h #define SlotVisitor_h +#include "BumpSpace.h" #include "MarkStack.h" namespace JSC { @@ -59,8 +60,15 @@ public: void harvestWeakReferences(); void finalizeUnconditionalFinalizers(); + + void startCopying(); + void copy(void**, size_t); + void copyAndAppend(void**, size_t, JSValue*, unsigned); + void doneCopying(); private: + void* allocateNewSpace(void*, size_t); + void donateSlow(); void donateKnownParallel() @@ -69,10 +77,13 @@ private: return; donateSlow(); } + + BumpBlock* m_copyBlock; }; inline SlotVisitor::SlotVisitor(MarkStackThreadSharedData& shared) : MarkStack(shared) + , m_copyBlock(0) { } diff --git a/Source/JavaScriptCore/heap/TinyBloomFilter.h b/Source/JavaScriptCore/heap/TinyBloomFilter.h index 82b586309..a75ce8ce5 100644 --- a/Source/JavaScriptCore/heap/TinyBloomFilter.h +++ b/Source/JavaScriptCore/heap/TinyBloomFilter.h @@ -36,6 +36,7 @@ public: void add(Bits); bool ruleOut(Bits) const; // True for 0. + void reset(); private: Bits m_bits; @@ -62,6 +63,11 @@ inline bool TinyBloomFilter::ruleOut(Bits bits) const return false; } +inline void TinyBloomFilter::reset() +{ + m_bits = 0; +} + } // namespace JSC #endif // TinyBloomFilter_h diff --git a/Source/JavaScriptCore/heap/VTableSpectrum.h b/Source/JavaScriptCore/heap/VTableSpectrum.h index 8a9737e9b..a50a04f47 100644 --- a/Source/JavaScriptCore/heap/VTableSpectrum.h +++ b/Source/JavaScriptCore/heap/VTableSpectrum.h @@ -39,7 +39,7 @@ public: ~VTableSpectrum(); void countVPtr(void*); - void count(JSCell*); + JS_EXPORT_PRIVATE void count(JSCell*); void dump(FILE* output, const char* comment); }; diff --git a/Source/JavaScriptCore/heap/WriteBarrierSupport.h b/Source/JavaScriptCore/heap/WriteBarrierSupport.h index 00b9bb97f..5d7d2f6fe 100644 --- a/Source/JavaScriptCore/heap/WriteBarrierSupport.h +++ b/Source/JavaScriptCore/heap/WriteBarrierSupport.h @@ -81,8 +81,8 @@ public: } #else // These are necessary to work around not having conditional exports. - static char usesWithBarrierFromCpp; - static char usesWithoutBarrierFromCpp; + JS_EXPORTDATA static char usesWithBarrierFromCpp; + JS_EXPORTDATA static char usesWithoutBarrierFromCpp; #endif // ENABLE(WRITE_BARRIER_PROFILING) static void countWriteBarrier() diff --git a/Source/JavaScriptCore/interpreter/AbstractPC.cpp b/Source/JavaScriptCore/interpreter/AbstractPC.cpp new file mode 100644 index 000000000..863915bda --- /dev/null +++ b/Source/JavaScriptCore/interpreter/AbstractPC.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AbstractPC.h" + +#include "CallFrame.h" +#include "JSGlobalData.h" +#include "JSObject.h" +#include "ScopeChain.h" + +namespace JSC { + +AbstractPC::AbstractPC(JSGlobalData& globalData, ExecState* exec) +{ + UNUSED_PARAM(globalData); + +#if ENABLE(JIT) + if (globalData.canUseJIT()) { + m_pointer = exec->returnPC().value(); + m_mode = JIT; + return; + } +#endif + +#if ENABLE(INTERPRETER) + m_pointer = exec->returnVPC(); + m_mode = Interpreter; +#endif +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/interpreter/AbstractPC.h b/Source/JavaScriptCore/interpreter/AbstractPC.h new file mode 100644 index 000000000..dffaaf343 --- /dev/null +++ b/Source/JavaScriptCore/interpreter/AbstractPC.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 AbstractPC_h +#define AbstractPC_h + +#include "MacroAssemblerCodeRef.h" +#include <wtf/Platform.h> + +namespace JSC { + +class JSGlobalData; +class ExecState; +struct Instruction; + +class AbstractPC { +public: + AbstractPC() + : m_pointer(0) + , m_mode(None) + { + } + + AbstractPC(JSGlobalData&, ExecState*); + +#if ENABLE(JIT) + AbstractPC(ReturnAddressPtr ptr) + : m_pointer(ptr.value()) + , m_mode(JIT) + { + } + + bool hasJITReturnAddress() const { return m_mode == JIT; } + ReturnAddressPtr jitReturnAddress() const + { + ASSERT(hasJITReturnAddress()); + return ReturnAddressPtr(m_pointer); + } +#endif + +#if ENABLE(INTERPRETER) + AbstractPC(Instruction* vPC) + : m_pointer(vPC) + , m_mode(Interpreter) + { + } + + bool hasInterpreterReturnAddress() const { return m_mode == Interpreter; } + Instruction* interpreterReturnAddress() const + { + ASSERT(hasInterpreterReturnAddress()); + return static_cast<Instruction*>(m_pointer); + } +#endif + + bool isSet() const { return m_mode != None; } + bool operator!() const { return !isSet(); } + +private: + void* m_pointer; + + enum Mode { None, JIT, Interpreter }; + Mode m_mode; +}; + +} // namespace JSC + +#endif // AbstractPC_h + diff --git a/Source/JavaScriptCore/interpreter/CallFrame.cpp b/Source/JavaScriptCore/interpreter/CallFrame.cpp index 6dba77898..3ef5bd26f 100644 --- a/Source/JavaScriptCore/interpreter/CallFrame.cpp +++ b/Source/JavaScriptCore/interpreter/CallFrame.cpp @@ -61,53 +61,66 @@ bool CallFrame::isInlineCallFrameSlow() JSFunction* calleeAsFunction = asFunction(calleeAsFunctionCell); return calleeAsFunction->executable() != codeBlock()->ownerExecutable(); } - -CallFrame* CallFrame::trueCallerFrame() + +CallFrame* CallFrame::trueCallFrame(AbstractPC pc) { - // this -> The callee; this is either an inlined callee in which case it already has - // a pointer to the true caller. Otherwise it contains current PC in the machine - // caller. - // - // machineCaller -> The caller according to the machine, which may be zero or - // more frames above the true caller due to inlining. - // - // trueCaller -> The real caller. - // Am I an inline call frame? If so, we're done. if (isInlineCallFrame()) - return callerFrame(); + return this; - // I am a machine call frame, so the question is: is my caller a machine call frame - // that has inlines or a machine call frame that doesn't? - CallFrame* machineCaller = callerFrame()->removeHostCallFrameFlag(); - if (!machineCaller) - return 0; - ASSERT(!machineCaller->isInlineCallFrame()); - if (!machineCaller->codeBlock()) - return machineCaller; - if (!machineCaller->codeBlock()->hasCodeOrigins()) - return machineCaller; // No inlining, so machineCaller == trueCaller + // If I don't have a code block, then I'm not DFG code, so I'm the true call frame. + CodeBlock* machineCodeBlock = codeBlock(); + if (!machineCodeBlock) + return this; - // Figure out where the caller frame would have gone relative to the machine - // caller, and rematerialize it. Do so for the entire inline stack. + // If the code block does not have any code origins, then there was no inlining, so + // I'm done. + if (!machineCodeBlock->hasCodeOrigins()) + return this; - CodeOrigin codeOrigin = machineCaller->codeBlock()->codeOriginForReturn(returnPC()); + // At this point the PC must be due either to the DFG, or it must be unset. + ASSERT(pc.hasJITReturnAddress() || !pc); + + // Try to determine the CodeOrigin. If we don't have a pc set then the only way + // that this makes sense is if the CodeOrigin index was set in the call frame. + // FIXME: Note that you will see "Not currently in inlined code" comments below. + // Currently, we do not record code origins for code that is not inlined, because + // the only thing that we use code origins for is determining the inline stack. + // But in the future, we'll want to use this same functionality (having a code + // origin mapping for any calls out of JIT code) to determine the PC at any point + // in the stack even if not in inlined code. When that happens, the code below + // will have to change the way it detects the presence of inlining: it will always + // get a code origin, but sometimes, that code origin will not have an inline call + // frame. In that case, this method should bail and return this. + CodeOrigin codeOrigin; + if (pc.isSet()) { + ReturnAddressPtr currentReturnPC = pc.jitReturnAddress(); + + if (!machineCodeBlock->codeOriginForReturn(currentReturnPC, codeOrigin)) + return this; // Not currently in inlined code. + } else { + unsigned index = codeOriginIndexForDFGWithInlining(); + if (index == UINT_MAX) + return this; // Not currently in inlined code. + + codeOrigin = machineCodeBlock->codeOrigin(index); + } for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) { InlineCallFrame* nextInlineCallFrame = inlineCallFrame->caller.inlineCallFrame; - CallFrame* inlinedCaller = machineCaller + inlineCallFrame->stackOffset; + CallFrame* inlinedCaller = this + inlineCallFrame->stackOffset; JSFunction* calleeAsFunction = inlineCallFrame->callee.get(); // Fill in the inlinedCaller - inlinedCaller->setCodeBlock(machineCaller->codeBlock()); + inlinedCaller->setCodeBlock(machineCodeBlock); inlinedCaller->setScopeChain(calleeAsFunction->scope()); if (nextInlineCallFrame) - inlinedCaller->setCallerFrame(machineCaller + nextInlineCallFrame->stackOffset); + inlinedCaller->setCallerFrame(this + nextInlineCallFrame->stackOffset); else - inlinedCaller->setCallerFrame(machineCaller); + inlinedCaller->setCallerFrame(this); inlinedCaller->setInlineCallFrame(inlineCallFrame); inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->arguments.size()); @@ -116,7 +129,34 @@ CallFrame* CallFrame::trueCallerFrame() inlineCallFrame = nextInlineCallFrame; } - return machineCaller + codeOrigin.inlineCallFrame->stackOffset; + return this + codeOrigin.inlineCallFrame->stackOffset; +} + +CallFrame* CallFrame::trueCallerFrame() +{ + // this -> The callee; this is either an inlined callee in which case it already has + // a pointer to the true caller. Otherwise it contains current PC in the machine + // caller. + // + // machineCaller -> The caller according to the machine, which may be zero or + // more frames above the true caller due to inlining. + + // Am I an inline call frame? If so, we're done. + if (isInlineCallFrame()) + return callerFrame(); + + // I am a machine call frame, so the question is: is my caller a machine call frame + // that has inlines or a machine call frame that doesn't? + CallFrame* machineCaller = callerFrame()->removeHostCallFrameFlag(); + if (!machineCaller) + return 0; + ASSERT(!machineCaller->isInlineCallFrame()); + + // Figure out how we want to get the current code location. + if (hasHostCallFrameFlag() || returnAddressIsInCtiTrampoline(returnPC())) + return machineCaller->trueCallFrameFromVMCode(); + + return machineCaller->trueCallFrame(returnPC()); } #endif diff --git a/Source/JavaScriptCore/interpreter/CallFrame.h b/Source/JavaScriptCore/interpreter/CallFrame.h index d5037b794..e0a291f8b 100644 --- a/Source/JavaScriptCore/interpreter/CallFrame.h +++ b/Source/JavaScriptCore/interpreter/CallFrame.h @@ -23,6 +23,7 @@ #ifndef CallFrame_h #define CallFrame_h +#include "AbstractPC.h" #include "JSGlobalData.h" #include "MacroAssemblerCodeRef.h" #include "RegisterFile.h" @@ -104,8 +105,10 @@ namespace JSC { #if ENABLE(JIT) ReturnAddressPtr returnPC() const { return ReturnAddressPtr(this[RegisterFile::ReturnPC].vPC()); } #endif + AbstractPC abstractReturnPC(JSGlobalData& globalData) { return AbstractPC(globalData, this); } #if ENABLE(DFG_JIT) InlineCallFrame* inlineCallFrame() const { return this[RegisterFile::ReturnPC].asInlineCallFrame(); } + unsigned codeOriginIndexForDFGWithInlining() const { return this[RegisterFile::ArgumentCount].tag(); } #else // This will never be called if !ENABLE(DFG_JIT) since all calls should be guarded by // isInlineCallFrame(). But to make it easier to write code without having a bunch of @@ -185,14 +188,30 @@ namespace JSC { void setInlineCallFrame(InlineCallFrame* inlineCallFrame) { static_cast<Register*>(this)[RegisterFile::ReturnPC] = inlineCallFrame; } - // Call this to get the semantically correct JS CallFrame*. This resolves issues - // surrounding inlining and the HostCallFrameFlag stuff. + // Call this to get the semantically correct JS CallFrame* for the + // currently executing function. + CallFrame* trueCallFrame(AbstractPC); + + // Call this to get the semantically correct JS CallFrame* corresponding + // to the caller. This resolves issues surrounding inlining and the + // HostCallFrameFlag stuff. CallFrame* trueCallerFrame(); #else bool isInlineCallFrame() { return false; } + CallFrame* trueCallFrame(AbstractPC) { return this; } CallFrame* trueCallerFrame() { return callerFrame()->removeHostCallFrameFlag(); } #endif + + // Call this to get the true call frame (accounted for inlining and any + // other optimizations), when you have entered into VM code through one + // of the "blessed" entrypoints (JITStubs or DFGOperations). This means + // that if you're pretty much anywhere in the VM you can safely call this; + // though if you were to magically get an ExecState* by, say, interrupting + // a thread that is running JS code and brutishly scraped the call frame + // register, calling this method would probably lead to horrible things + // happening. + CallFrame* trueCallFrameFromVMCode() { return trueCallFrame(AbstractPC()); } private: static const intptr_t HostCallFrameFlag = 1; diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index 980bf8a1a..51843f2d2 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -905,7 +905,7 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, S PutPropertySlot slot; globalObject->methodTable()->put(globalObject, callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, slot); } else - globalObject->methodTable()->putWithAttributes(globalObject, callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, DontEnum | DontDelete); + globalObject->methodTable()->putDirectVirtual(globalObject, callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, DontEnum | DontDelete); // var declarations return undefined result = jsUndefined(); continue; @@ -1324,7 +1324,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue JSObject* variableObject; for (ScopeChainNode* node = scopeChain; ; node = node->next.get()) { ASSERT(node); - if (node->object->isVariableObject()) { + if (node->object->isVariableObject() && !node->object->isStaticScopeObject()) { variableObject = static_cast<JSVariableObject*>(node->object.get()); break; } @@ -2579,7 +2579,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (propName.getUInt32(i)) callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, i)); else { - Identifier property(callFrame, propName.toString(callFrame)); + Identifier property(callFrame, propName.toString(callFrame)->value(callFrame)); CHECK_FOR_EXCEPTION(); callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, property)); } @@ -3310,9 +3310,10 @@ skip_id_custom_self: JSValue baseValue = callFrame->r(base).jsValue(); Identifier& ident = codeBlock->identifier(property); PutPropertySlot slot(codeBlock->isStrictMode()); - if (direct) - baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot); - else + if (direct) { + ASSERT(baseValue.isObject()); + asObject(baseValue)->putDirect(*globalData, ident, callFrame->r(value).jsValue(), slot); + } else baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot); CHECK_FOR_EXCEPTION(); @@ -3428,9 +3429,10 @@ skip_id_custom_self: JSValue baseValue = callFrame->r(base).jsValue(); Identifier& ident = codeBlock->identifier(property); PutPropertySlot slot(codeBlock->isStrictMode()); - if (direct) - baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot); - else + if (direct) { + ASSERT(baseValue.isObject()); + asObject(baseValue)->putDirect(*globalData, ident, callFrame->r(value).jsValue(), slot); + } else baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot); CHECK_FOR_EXCEPTION(); @@ -3482,7 +3484,7 @@ skip_id_custom_self: NEXT_INSTRUCTION(); } { - Identifier propertyName(callFrame, subscript.toString(callFrame)); + Identifier propertyName(callFrame, subscript.toString(callFrame)->value(callFrame)); result = baseValue.get(callFrame, propertyName); } CHECK_FOR_EXCEPTION(); @@ -3557,7 +3559,7 @@ skip_id_custom_self: else result = baseValue.get(callFrame, i); } else { - Identifier property(callFrame, subscript.toString(callFrame)); + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); result = baseValue.get(callFrame, property); } @@ -3604,7 +3606,7 @@ skip_id_custom_self: } else baseValue.put(callFrame, i, callFrame->r(value).jsValue()); } else { - Identifier property(callFrame, subscript.toString(callFrame)); + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); if (!globalData->exception) { // Don't put to an object if toString threw an exception. PutPropertySlot slot(codeBlock->isStrictMode()); baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot); @@ -3636,7 +3638,7 @@ skip_id_custom_self: result = baseObj->methodTable()->deletePropertyByIndex(baseObj, callFrame, i); else { CHECK_FOR_EXCEPTION(); - Identifier property(callFrame, subscript.toString(callFrame)); + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); CHECK_FOR_EXCEPTION(); result = baseObj->methodTable()->deleteProperty(baseObj, callFrame, property); } @@ -4943,7 +4945,7 @@ skip_id_custom_self: original constructor, using constant message as the message string. The result is thrown. */ - UString message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame); + UString message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame)->value(callFrame); exceptionValue = JSValue(createReferenceError(callFrame, message)); goto vm_throw; } @@ -4957,52 +4959,41 @@ skip_id_custom_self: int result = vPC[1].u.operand; return callFrame->r(result).jsValue(); } - DEFINE_OPCODE(op_put_getter) { - /* put_getter base(r) property(id) function(r) + DEFINE_OPCODE(op_put_getter_setter) { + /* put_getter_setter base(r) property(id) getter(r) setter(r) - Sets register function on register base as the getter named - by identifier property. Base and function are assumed to be - objects as this op should only be used for getters defined - in object literal form. + Puts accessor descriptor to register base as the named + identifier property. Base and function may be objects + or undefined, this op should only be used for accessors + defined in object literal form. Unlike many opcodes, this one does not write any output to the register file. */ int base = vPC[1].u.operand; int property = vPC[2].u.operand; - int function = vPC[3].u.operand; + int getterReg = vPC[3].u.operand; + int setterReg = vPC[4].u.operand; ASSERT(callFrame->r(base).jsValue().isObject()); JSObject* baseObj = asObject(callFrame->r(base).jsValue()); Identifier& ident = codeBlock->identifier(property); - ASSERT(callFrame->r(function).jsValue().isObject()); - baseObj->methodTable()->defineGetter(baseObj, callFrame, ident, asObject(callFrame->r(function).jsValue()), 0); - vPC += OPCODE_LENGTH(op_put_getter); - NEXT_INSTRUCTION(); - } - DEFINE_OPCODE(op_put_setter) { - /* put_setter base(r) property(id) function(r) + GetterSetter* accessor = GetterSetter::create(callFrame); - Sets register function on register base as the setter named - by identifier property. Base and function are assumed to be - objects as this op should only be used for setters defined - in object literal form. + JSValue getter = callFrame->r(getterReg).jsValue(); + JSValue setter = callFrame->r(setterReg).jsValue(); + ASSERT(getter.isObject() || getter.isUndefined()); + ASSERT(setter.isObject() || setter.isUndefined()); + ASSERT(getter.isObject() || setter.isObject()); - Unlike many opcodes, this one does not write any output to - the register file. - */ - int base = vPC[1].u.operand; - int property = vPC[2].u.operand; - int function = vPC[3].u.operand; - - ASSERT(callFrame->r(base).jsValue().isObject()); - JSObject* baseObj = asObject(callFrame->r(base).jsValue()); - Identifier& ident = codeBlock->identifier(property); - ASSERT(callFrame->r(function).jsValue().isObject()); - baseObj->methodTable()->defineSetter(baseObj, callFrame, ident, asObject(callFrame->r(function).jsValue()), 0); + if (!getter.isUndefined()) + accessor->setGetter(callFrame->globalData(), asObject(getter)); + if (!setter.isUndefined()) + accessor->setSetter(callFrame->globalData(), asObject(setter)); + baseObj->putDirectAccessor(callFrame->globalData(), ident, accessor, Accessor); - vPC += OPCODE_LENGTH(op_put_setter); + vPC += OPCODE_LENGTH(op_put_getter_setter); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_method_check) { @@ -5106,9 +5097,9 @@ skip_id_custom_self: #endif // ENABLE(INTERPRETER) } -JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const +JSValue Interpreter::retrieveArgumentsFromVMCode(CallFrame* callFrame, JSFunction* function) const { - CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function); + CallFrame* functionCallFrame = findFunctionCallFrameFromVMCode(callFrame, function); if (!functionCallFrame) return jsNull(); @@ -5130,9 +5121,9 @@ JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* functio return JSValue(arguments); } -JSValue Interpreter::retrieveCaller(CallFrame* callFrame, JSFunction* function) const +JSValue Interpreter::retrieveCallerFromVMCode(CallFrame* callFrame, JSFunction* function) const { - CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function); + CallFrame* functionCallFrame = findFunctionCallFrameFromVMCode(callFrame, function); if (!functionCallFrame) return jsNull(); @@ -5177,9 +5168,9 @@ void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intp function = callerFrame->callee(); } -CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, JSFunction* function) +CallFrame* Interpreter::findFunctionCallFrameFromVMCode(CallFrame* callFrame, JSFunction* function) { - for (CallFrame* candidate = callFrame; candidate; candidate = candidate->trueCallerFrame()) { + for (CallFrame* candidate = callFrame->trueCallFrameFromVMCode(); candidate; candidate = candidate->trueCallerFrame()) { if (candidate->callee() == function) return candidate; } diff --git a/Source/JavaScriptCore/interpreter/Interpreter.h b/Source/JavaScriptCore/interpreter/Interpreter.h index 6dfd331f8..1943513ae 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.h +++ b/Source/JavaScriptCore/interpreter/Interpreter.h @@ -79,6 +79,16 @@ namespace JSC { JSGlobalData& globalData; CallFrame* oldCallFrame; }; + + class NativeCallFrameTracer { + public: + ALWAYS_INLINE NativeCallFrameTracer(JSGlobalData* global, CallFrame* callFrame) + { + ASSERT(global); + ASSERT(callFrame); + global->topCallFrame = callFrame; + } + }; #if PLATFORM(IOS) // We use a smaller reentrancy limit on iPhone because of the high amount of @@ -131,8 +141,8 @@ namespace JSC { JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, ScopeChainNode*); JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, ScopeChainNode*, int globalRegisterOffset); - JSValue retrieveArguments(CallFrame*, JSFunction*) const; - JS_EXPORT_PRIVATE JSValue retrieveCaller(CallFrame*, JSFunction*) const; + JSValue retrieveArgumentsFromVMCode(CallFrame*, JSFunction*) const; + JS_EXPORT_PRIVATE JSValue retrieveCallerFromVMCode(CallFrame*, JSFunction*) const; JS_EXPORT_PRIVATE void retrieveLastCaller(CallFrame*, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const; void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc); @@ -172,7 +182,7 @@ namespace JSC { static ALWAYS_INLINE CallFrame* slideRegisterWindowForCall(CodeBlock*, RegisterFile*, CallFrame*, size_t registerOffset, int argc); - static CallFrame* findFunctionCallFrame(CallFrame*, JSFunction*); + static CallFrame* findFunctionCallFrameFromVMCode(CallFrame*, JSFunction*); JSValue privateExecute(ExecutionFlag, RegisterFile*, CallFrame*); diff --git a/Source/JavaScriptCore/jit/ExecutableAllocator.cpp b/Source/JavaScriptCore/jit/ExecutableAllocator.cpp index 82c149d0e..75137279e 100644 --- a/Source/JavaScriptCore/jit/ExecutableAllocator.cpp +++ b/Source/JavaScriptCore/jit/ExecutableAllocator.cpp @@ -28,6 +28,7 @@ #include "ExecutableAllocator.h" #if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND) +#include "CodeProfiling.h" #include <wtf/MetaAllocator.h> #include <wtf/PageReservation.h> #include <wtf/VMTags.h> @@ -93,6 +94,7 @@ void ExecutableAllocator::initializeAllocator() { ASSERT(!allocator); allocator = new DemandExecutableAllocator(); + CodeProfiling::notifyAllocator(allocator); } ExecutableAllocator::ExecutableAllocator(JSGlobalData&) @@ -110,9 +112,9 @@ bool ExecutableAllocator::underMemoryPressure() return false; } -PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(JSGlobalData&, size_t sizeInBytes) +PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(JSGlobalData&, size_t sizeInBytes, void* ownerUID) { - RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes); + RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes, ownerUID); if (!result) CRASH(); return result.release(); diff --git a/Source/JavaScriptCore/jit/ExecutableAllocator.h b/Source/JavaScriptCore/jit/ExecutableAllocator.h index 876bda62e..bc8b816c8 100644 --- a/Source/JavaScriptCore/jit/ExecutableAllocator.h +++ b/Source/JavaScriptCore/jit/ExecutableAllocator.h @@ -113,7 +113,7 @@ public: static void dumpProfile() { } #endif - PassRefPtr<ExecutableMemoryHandle> allocate(JSGlobalData&, size_t sizeInBytes); + PassRefPtr<ExecutableMemoryHandle> allocate(JSGlobalData&, size_t sizeInBytes, void* ownerUID); #if ENABLE(ASSEMBLER_WX_EXCLUSIVE) static void makeWritable(void* start, size_t size) @@ -130,7 +130,6 @@ public: static void makeExecutable(void*, size_t) {} #endif - #if CPU(X86) || CPU(X86_64) static void cacheFlush(void*, size_t) { diff --git a/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp b/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp index 3771c74a9..3fe631e3b 100644 --- a/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp +++ b/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp @@ -29,8 +29,8 @@ #if ENABLE(EXECUTABLE_ALLOCATOR_FIXED) +#include "CodeProfiling.h" #include <errno.h> - #include <sys/mman.h> #include <unistd.h> #include <wtf/MetaAllocator.h> @@ -96,6 +96,7 @@ void ExecutableAllocator::initializeAllocator() { ASSERT(!allocator); allocator = new FixedVMPoolExecutableAllocator(); + CodeProfiling::notifyAllocator(allocator); } ExecutableAllocator::ExecutableAllocator(JSGlobalData&) @@ -114,12 +115,12 @@ bool ExecutableAllocator::underMemoryPressure() return statistics.bytesAllocated > statistics.bytesReserved / 2; } -PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(JSGlobalData& globalData, size_t sizeInBytes) +PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(JSGlobalData& globalData, size_t sizeInBytes, void* ownerUID) { - RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes); + RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes, ownerUID); if (!result) { releaseExecutableMemory(globalData); - result = allocator->allocate(sizeInBytes); + result = allocator->allocate(sizeInBytes, ownerUID); if (!result) CRASH(); } diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp index 025b5b706..247495aaf 100644 --- a/Source/JavaScriptCore/jit/JIT.cpp +++ b/Source/JavaScriptCore/jit/JIT.cpp @@ -99,7 +99,7 @@ void JIT::emitOptimizationCheck(OptimizationCheckKind kind) if (!shouldEmitProfiling()) return; - Jump skipOptimize = branchAdd32(Signed, TrustedImm32(kind == LoopOptimizationCheck ? Options::executionCounterIncrementForLoop : Options::executionCounterIncrementForReturn), AbsoluteAddress(m_codeBlock->addressOfExecuteCounter())); + Jump skipOptimize = branchAdd32(Signed, TrustedImm32(kind == LoopOptimizationCheck ? Options::executionCounterIncrementForLoop : Options::executionCounterIncrementForReturn), AbsoluteAddress(m_codeBlock->addressOfJITExecuteCounter())); JITStubCall stubCall(this, kind == LoopOptimizationCheck ? cti_optimize_from_loop : cti_optimize_from_ret); if (kind == LoopOptimizationCheck) stubCall.addArgument(Imm32(m_bytecodeOffset)); @@ -328,10 +328,9 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_put_by_id) DEFINE_OP(op_put_by_index) DEFINE_OP(op_put_by_val) - DEFINE_OP(op_put_getter) + DEFINE_OP(op_put_getter_setter) DEFINE_OP(op_put_global_var) DEFINE_OP(op_put_scoped_var) - DEFINE_OP(op_put_setter) DEFINE_OP(op_resolve) DEFINE_OP(op_resolve_base) DEFINE_OP(op_ensure_property_exists) @@ -614,7 +613,7 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck) ASSERT(m_jmpTable.isEmpty()); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); // Translate vPC offsets into addresses in JIT generated code, for switch tables. for (unsigned i = 0; i < m_switches.size(); ++i) { diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h index 750b9d818..c357e8c39 100644 --- a/Source/JavaScriptCore/jit/JIT.h +++ b/Source/JavaScriptCore/jit/JIT.h @@ -333,14 +333,15 @@ namespace JSC { template<typename T> void emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID storagePtr); void emitAllocateJSFunction(FunctionExecutable*, RegisterID scopeChain, RegisterID result, RegisterID storagePtr); - enum ValueProfilingSiteKind { FirstProfilingSite, SubsequentProfilingSite }; #if ENABLE(VALUE_PROFILER) // This assumes that the value to profile is in regT0 and that regT3 is available for // scratch. void emitValueProfilingSite(ValueProfile*); - void emitValueProfilingSite(ValueProfilingSiteKind); + void emitValueProfilingSite(unsigned bytecodeOffset); + void emitValueProfilingSite(); #else - void emitValueProfilingSite(ValueProfilingSiteKind) { } + void emitValueProfilingSite(unsigned) { } + void emitValueProfilingSite() { } #endif #if USE(JSVALUE32_64) @@ -856,10 +857,9 @@ namespace JSC { void emit_op_put_by_id(Instruction*); void emit_op_put_by_index(Instruction*); void emit_op_put_by_val(Instruction*); - void emit_op_put_getter(Instruction*); + void emit_op_put_getter_setter(Instruction*); void emit_op_put_global_var(Instruction*); void emit_op_put_scoped_var(Instruction*); - void emit_op_put_setter(Instruction*); void emit_op_resolve(Instruction*); void emit_op_resolve_base(Instruction*); void emit_op_ensure_property_exists(Instruction*); diff --git a/Source/JavaScriptCore/jit/JITCall.cpp b/Source/JavaScriptCore/jit/JITCall.cpp index 465f1add8..69dc9540e 100644 --- a/Source/JavaScriptCore/jit/JITCall.cpp +++ b/Source/JavaScriptCore/jit/JITCall.cpp @@ -50,8 +50,10 @@ namespace JSC { void JIT::emit_op_call_put_result(Instruction* instruction) { int dst = instruction[1].u.operand; - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(dst); + if (canBeOptimized()) + killLastResultRegister(); // Make lastResultRegister tracking simpler in the DFG. } void JIT::compileLoadVarargs(Instruction* instruction) diff --git a/Source/JavaScriptCore/jit/JITCall32_64.cpp b/Source/JavaScriptCore/jit/JITCall32_64.cpp index 01c9db094..b84ad1a49 100644 --- a/Source/JavaScriptCore/jit/JITCall32_64.cpp +++ b/Source/JavaScriptCore/jit/JITCall32_64.cpp @@ -50,7 +50,7 @@ namespace JSC { void JIT::emit_op_call_put_result(Instruction* instruction) { int dst = instruction[1].u.operand; - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitStore(dst, regT1, regT0); } diff --git a/Source/JavaScriptCore/jit/JITDriver.h b/Source/JavaScriptCore/jit/JITDriver.h new file mode 100644 index 000000000..7e010cdfe --- /dev/null +++ b/Source/JavaScriptCore/jit/JITDriver.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 JITDriver_h +#define JITDriver_h + +#include <wtf/Platform.h> + +#if ENABLE(JIT) + +#include "BytecodeGenerator.h" +#include "DFGDriver.h" +#include "JIT.h" + +namespace JSC { + +template<typename CodeBlockType> +inline bool jitCompileIfAppropriate(JSGlobalData& globalData, OwnPtr<CodeBlockType>& codeBlock, JITCode& jitCode, JITCode::JITType jitType) +{ + if (!globalData.canUseJIT()) + return true; + + bool dfgCompiled = false; + if (jitType == JITCode::DFGJIT) + dfgCompiled = DFG::tryCompile(globalData, codeBlock.get(), jitCode); + if (dfgCompiled) { + if (codeBlock->alternative()) + codeBlock->alternative()->unlinkIncomingCalls(); + } else { + if (codeBlock->alternative()) { + codeBlock = static_pointer_cast<CodeBlockType>(codeBlock->releaseAlternative()); + return false; + } + jitCode = JIT::compile(&globalData, codeBlock.get()); + } +#if !ENABLE(OPCODE_SAMPLING) + if (!BytecodeGenerator::dumpsGeneratedCode()) + codeBlock->handleBytecodeDiscardingOpportunity(); +#endif + codeBlock->setJITCode(jitCode, MacroAssemblerCodePtr()); + + return true; +} + +inline bool jitCompileFunctionIfAppropriate(JSGlobalData& globalData, OwnPtr<FunctionCodeBlock>& codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, SharedSymbolTable*& symbolTable, JITCode::JITType jitType) +{ + if (!globalData.canUseJIT()) + return true; + + bool dfgCompiled = false; + if (jitType == JITCode::DFGJIT) + dfgCompiled = DFG::tryCompileFunction(globalData, codeBlock.get(), jitCode, jitCodeWithArityCheck); + if (dfgCompiled) { + if (codeBlock->alternative()) + codeBlock->alternative()->unlinkIncomingCalls(); + } else { + if (codeBlock->alternative()) { + codeBlock = static_pointer_cast<FunctionCodeBlock>(codeBlock->releaseAlternative()); + symbolTable = codeBlock->sharedSymbolTable(); + return false; + } + jitCode = JIT::compile(&globalData, codeBlock.get(), &jitCodeWithArityCheck); + } +#if !ENABLE(OPCODE_SAMPLING) + if (!BytecodeGenerator::dumpsGeneratedCode()) + codeBlock->handleBytecodeDiscardingOpportunity(); +#endif + + codeBlock->setJITCode(jitCode, jitCodeWithArityCheck); + + return true; +} + +} // namespace JSC + +#endif // ENABLE(JIT) + +#endif // JITDriver_h + diff --git a/Source/JavaScriptCore/jit/JITInlineMethods.h b/Source/JavaScriptCore/jit/JITInlineMethods.h index 5540ffab3..e617961b5 100644 --- a/Source/JavaScriptCore/jit/JITInlineMethods.h +++ b/Source/JavaScriptCore/jit/JITInlineMethods.h @@ -486,20 +486,16 @@ inline void JIT::emitValueProfilingSite(ValueProfile* valueProfile) #endif } -inline void JIT::emitValueProfilingSite(ValueProfilingSiteKind siteKind) +inline void JIT::emitValueProfilingSite(unsigned bytecodeOffset) { if (!shouldEmitProfiling()) return; - - ValueProfile* valueProfile; - if (siteKind == FirstProfilingSite) - valueProfile = m_codeBlock->addValueProfile(m_bytecodeOffset); - else { - ASSERT(siteKind == SubsequentProfilingSite); - valueProfile = m_codeBlock->valueProfileForBytecodeOffset(m_bytecodeOffset); - } - - emitValueProfilingSite(valueProfile); + emitValueProfilingSite(m_codeBlock->valueProfileForBytecodeOffset(bytecodeOffset)); +} + +inline void JIT::emitValueProfilingSite() +{ + emitValueProfilingSite(m_bytecodeOffset); } #endif diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp index f5be279a6..8a2077e47 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp @@ -194,7 +194,7 @@ PassRefPtr<ExecutableMemoryHandle> JIT::privateCompileCTIMachineTrampolines(JSGl Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3); // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, GLOBAL_THUNK_ID); patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail)); patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail)); @@ -568,7 +568,7 @@ void JIT::emit_op_resolve(Instruction* currentInstruction) { JITStubCall stubCall(this, cti_op_resolve); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_to_primitive(Instruction* currentInstruction) @@ -599,7 +599,7 @@ void JIT::emit_op_resolve_base(Instruction* currentInstruction) { JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction) @@ -615,7 +615,7 @@ void JIT::emit_op_resolve_skip(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_resolve_skip); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool) @@ -636,7 +636,7 @@ void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool) loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_propertyStorage)), regT0); load32(Address(regT2, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), regT1); loadPtr(BaseIndex(regT0, regT1, ScalePtr), regT0); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(currentInstruction[1].u.operand); } @@ -652,7 +652,7 @@ void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<Slo stubCall.addArgument(TrustedImmPtr(ident)); stubCall.addArgument(Imm32(currentIndex)); stubCall.addArgument(regT0); - stubCall.callWithValueProfiling(dst, SubsequentProfilingSite); + stubCall.callWithValueProfiling(dst); } void JIT::emit_op_not(Instruction* currentInstruction) @@ -773,7 +773,7 @@ void JIT::emit_op_resolve_with_base(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_resolve_with_base); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[2].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[2].u.operand); } void JIT::emit_op_resolve_with_this(Instruction* currentInstruction) @@ -781,7 +781,7 @@ void JIT::emit_op_resolve_with_this(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_resolve_with_this); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[2].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[2].u.operand); } void JIT::emit_op_jtrue(Instruction* currentInstruction) @@ -1563,7 +1563,7 @@ void JIT::emitSlow_op_resolve_global_dynamic(Instruction* currentInstruction, Ve stubCall.addArgument(TrustedImmPtr(ident)); stubCall.addArgument(Imm32(currentIndex)); stubCall.addArgument(regT0); - stubCall.callWithValueProfiling(dst, SubsequentProfilingSite); // The first profiling site is in emit_op_resolve_global + stubCall.callWithValueProfiling(dst); } void JIT::emit_op_new_regexp(Instruction* currentInstruction) diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp index 9d1cbce8d..99594c3f1 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -193,7 +193,7 @@ PassRefPtr<ExecutableMemoryHandle> JIT::privateCompileCTIMachineTrampolines(JSGl Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3); // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, GLOBAL_THUNK_ID); patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail)); patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail)); @@ -492,7 +492,7 @@ JIT::CodeRef JIT::privateCompileCTINativeCall(JSGlobalData* globalData, NativeFu ret(); // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, GLOBAL_THUNK_ID); patchBuffer.link(nativeCall, FunctionPtr(func)); return patchBuffer.finalizeCode(); @@ -660,7 +660,7 @@ void JIT::emit_op_resolve(Instruction* currentInstruction) { JITStubCall stubCall(this, cti_op_resolve); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_to_primitive(Instruction* currentInstruction) @@ -702,7 +702,7 @@ void JIT::emit_op_resolve_base(Instruction* currentInstruction) { JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction) @@ -718,7 +718,7 @@ void JIT::emit_op_resolve_skip(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_resolve_skip); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool dynamic) @@ -743,7 +743,7 @@ void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool dynamic) load32(Address(regT3, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), regT3); load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + (dynamic ? OPCODE_LENGTH(op_resolve_global_dynamic) : OPCODE_LENGTH(op_resolve_global)), dst, regT1, regT0); } @@ -759,7 +759,7 @@ void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<Slo JITStubCall stubCall(this, cti_op_resolve_global); stubCall.addArgument(TrustedImmPtr(ident)); stubCall.addArgument(Imm32(currentIndex)); - stubCall.callWithValueProfiling(dst, SubsequentProfilingSite); + stubCall.callWithValueProfiling(dst); } void JIT::emit_op_not(Instruction* currentInstruction) @@ -1157,7 +1157,7 @@ void JIT::emit_op_resolve_with_base(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_resolve_with_base); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[2].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[2].u.operand); } void JIT::emit_op_resolve_with_this(Instruction* currentInstruction) @@ -1165,7 +1165,7 @@ void JIT::emit_op_resolve_with_this(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_resolve_with_this); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[2].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[2].u.operand); } void JIT::emit_op_throw(Instruction* currentInstruction) diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp index 48951e879..9fa29e2d9 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp @@ -86,7 +86,7 @@ JIT::CodeRef JIT::stringGetByValStubGenerator(JSGlobalData* globalData) jit.move(TrustedImm32(0), regT0); jit.ret(); - LinkBuffer patchBuffer(*globalData, &jit); + LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); return patchBuffer.finalizeCode(); } @@ -116,7 +116,7 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) loadPtr(BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); addSlowCase(branchTestPtr(Zero, regT0)); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(dst); } @@ -147,7 +147,7 @@ void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCas stubCall.addArgument(property, regT2); stubCall.call(dst); - emitValueProfilingSite(SubsequentProfilingSite); + emitValueProfilingSite(); } void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID offset, RegisterID scratch) @@ -261,21 +261,13 @@ void JIT::emit_op_put_by_index(Instruction* currentInstruction) stubCall.call(); } -void JIT::emit_op_put_getter(Instruction* currentInstruction) +void JIT::emit_op_put_getter_setter(Instruction* currentInstruction) { - JITStubCall stubCall(this, cti_op_put_getter); - stubCall.addArgument(currentInstruction[1].u.operand, regT2); - stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); - stubCall.addArgument(currentInstruction[3].u.operand, regT2); - stubCall.call(); -} - -void JIT::emit_op_put_setter(Instruction* currentInstruction) -{ - JITStubCall stubCall(this, cti_op_put_setter); + JITStubCall stubCall(this, cti_op_put_getter_setter); stubCall.addArgument(currentInstruction[1].u.operand, regT2); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); stubCall.addArgument(currentInstruction[3].u.operand, regT2); + stubCall.addArgument(currentInstruction[4].u.operand, regT2); stubCall.call(); } @@ -332,7 +324,7 @@ void JIT::emit_op_method_check(Instruction* currentInstruction) compileGetByIdHotPath(baseVReg, ident); match.link(this); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(m_bytecodeOffset + OPCODE_LENGTH(op_method_check)); emitPutVirtualRegister(resultVReg); // We've already generated the following get_by_id, so make sure it's skipped over. @@ -347,7 +339,7 @@ void JIT::emitSlow_op_method_check(Instruction* currentInstruction, Vector<SlowC Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand)); compileGetByIdSlowCase(resultVReg, baseVReg, ident, iter, true); - emitValueProfilingSite(SubsequentProfilingSite); + emitValueProfilingSite(m_bytecodeOffset + OPCODE_LENGTH(op_method_check)); // We've already generated the following get_by_id, so make sure it's skipped over. m_bytecodeOffset += OPCODE_LENGTH(op_get_by_id); @@ -361,7 +353,7 @@ void JIT::emit_op_get_by_id(Instruction* currentInstruction) emitGetVirtualRegister(baseVReg, regT0); compileGetByIdHotPath(baseVReg, ident); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(resultVReg); } @@ -405,7 +397,7 @@ void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCase Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand)); compileGetByIdSlowCase(resultVReg, baseVReg, ident, iter, false); - emitValueProfilingSite(SubsequentProfilingSite); + emitValueProfilingSite(); } void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, bool isMethodCheck) @@ -548,7 +540,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure stubCall.skipArgument(); // ident stubCall.skipArgument(); // value stubCall.addArgument(TrustedImm32(oldStructure->propertyStorageCapacity())); - stubCall.addArgument(TrustedImm32(newStructure->propertyStorageCapacity())); + stubCall.addArgument(TrustedImmPtr(newStructure)); stubCall.call(regT0); emitGetJITStubArg(2, regT1); @@ -570,7 +562,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure restoreArgumentReferenceForTrampoline(); Call failureCall = tailRecursiveCall(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail)); @@ -629,7 +621,7 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) emitFastArithIntToImmNoCheck(regT2, regT0); Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); // Use the patch information to link the failure cases back to the original slow case routine. CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); @@ -686,7 +678,7 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str } else compileGetDirectOffset(protoObject, regT0, cachedOffset); Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); // Use the patch information to link the failure cases back to the original slow case routine. CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); @@ -741,7 +733,7 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic } Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -809,7 +801,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -878,7 +870,7 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi } Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -946,7 +938,7 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str compileGetDirectOffset(protoObject, regT0, cachedOffset); Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -994,7 +986,7 @@ void JIT::emit_op_get_scoped_var(Instruction* currentInstruction) loadPtr(Address(regT0, OBJECT_OFFSETOF(ScopeChainNode, object)), regT0); loadPtr(Address(regT0, JSVariableObject::offsetOfRegisters()), regT0); loadPtr(Address(regT0, currentInstruction[2].u.operand * sizeof(Register)), regT0); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(currentInstruction[1].u.operand); } @@ -1029,7 +1021,7 @@ void JIT::emit_op_get_global_var(Instruction* currentInstruction) JSVariableObject* globalObject = m_codeBlock->globalObject(); loadPtr(&globalObject->m_registers, regT0); loadPtr(Address(regT0, currentInstruction[2].u.operand * sizeof(Register)), regT0); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(currentInstruction[1].u.operand); } diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp index b73d7ab75..2c81a5ff6 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp @@ -62,29 +62,18 @@ void JIT::emit_op_put_by_index(Instruction* currentInstruction) stubCall.call(); } -void JIT::emit_op_put_getter(Instruction* currentInstruction) +void JIT::emit_op_put_getter_setter(Instruction* currentInstruction) { unsigned base = currentInstruction[1].u.operand; unsigned property = currentInstruction[2].u.operand; - unsigned function = currentInstruction[3].u.operand; + unsigned getter = currentInstruction[3].u.operand; + unsigned setter = currentInstruction[4].u.operand; - JITStubCall stubCall(this, cti_op_put_getter); + JITStubCall stubCall(this, cti_op_put_getter_setter); stubCall.addArgument(base); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property))); - stubCall.addArgument(function); - stubCall.call(); -} - -void JIT::emit_op_put_setter(Instruction* currentInstruction) -{ - unsigned base = currentInstruction[1].u.operand; - unsigned property = currentInstruction[2].u.operand; - unsigned function = currentInstruction[3].u.operand; - - JITStubCall stubCall(this, cti_op_put_setter); - stubCall.addArgument(base); - stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property))); - stubCall.addArgument(function); + stubCall.addArgument(getter); + stubCall.addArgument(setter); stubCall.call(); } @@ -144,7 +133,7 @@ void JIT::emit_op_method_check(Instruction* currentInstruction) compileGetByIdHotPath(); match.link(this); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(m_bytecodeOffset + OPCODE_LENGTH(op_method_check)); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + OPCODE_LENGTH(op_method_check) + OPCODE_LENGTH(op_get_by_id), dst, regT1, regT0); @@ -161,7 +150,7 @@ void JIT::emitSlow_op_method_check(Instruction* currentInstruction, Vector<SlowC int ident = currentInstruction[3].u.operand; compileGetByIdSlowCase(dst, base, &(m_codeBlock->identifier(ident)), iter, true); - emitValueProfilingSite(SubsequentProfilingSite); + emitValueProfilingSite(m_bytecodeOffset + OPCODE_LENGTH(op_method_check)); // We've already generated the following get_by_id, so make sure it's skipped over. m_bytecodeOffset += OPCODE_LENGTH(op_get_by_id); @@ -205,7 +194,7 @@ JIT::CodeRef JIT::stringGetByValStubGenerator(JSGlobalData* globalData) jit.move(TrustedImm32(0), regT0); jit.ret(); - LinkBuffer patchBuffer(*globalData, &jit); + LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); return patchBuffer.finalizeCode(); } @@ -228,7 +217,7 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag))); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + OPCODE_LENGTH(op_get_by_val), dst, regT1, regT0); } @@ -261,7 +250,7 @@ void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCas stubCall.addArgument(property); stubCall.call(dst); - emitValueProfilingSite(SubsequentProfilingSite); + emitValueProfilingSite(); } void JIT::emit_op_put_by_val(Instruction* currentInstruction) @@ -325,7 +314,7 @@ void JIT::emit_op_get_by_id(Instruction* currentInstruction) emitLoad(base, regT1, regT0); emitJumpSlowCaseIfNotJSCell(base, regT1); compileGetByIdHotPath(); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + OPCODE_LENGTH(op_get_by_id), dst, regT1, regT0); } @@ -369,7 +358,7 @@ void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCase int ident = currentInstruction[3].u.operand; compileGetByIdSlowCase(dst, base, &(m_codeBlock->identifier(ident)), iter); - emitValueProfilingSite(SubsequentProfilingSite); + emitValueProfilingSite(); } void JIT::compileGetByIdSlowCase(int dst, int base, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, bool isMethodCheck) @@ -517,7 +506,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure stubCall.skipArgument(); // ident stubCall.skipArgument(); // value stubCall.addArgument(TrustedImm32(oldStructure->propertyStorageCapacity())); - stubCall.addArgument(TrustedImm32(newStructure->propertyStorageCapacity())); + stubCall.addArgument(TrustedImmPtr(newStructure)); stubCall.call(regT0); restoreReturnAddressBeforeReturn(regT3); @@ -553,7 +542,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure restoreArgumentReferenceForTrampoline(); Call failureCall = tailRecursiveCall(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail)); @@ -617,7 +606,7 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) move(TrustedImm32(JSValue::Int32Tag), regT1); Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); // Use the patch information to link the failure cases back to the original slow case routine. CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); @@ -676,7 +665,7 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); // Use the patch information to link the failure cases back to the original slow case routine. CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); @@ -735,7 +724,7 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { if (iter->to) @@ -802,7 +791,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { if (iter->to) @@ -872,7 +861,7 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { if (iter->to) @@ -939,7 +928,7 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset); Jump success = jump(); - LinkBuffer patchBuffer(*m_globalData, this); + LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock); if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { if (iter->to) @@ -1043,7 +1032,7 @@ void JIT::emit_op_get_scoped_var(Instruction* currentInstruction) loadPtr(Address(regT2, JSVariableObject::offsetOfRegisters()), regT2); emitLoad(index, regT1, regT0, regT2); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + OPCODE_LENGTH(op_get_scoped_var), dst, regT1, regT0); } @@ -1085,7 +1074,7 @@ void JIT::emit_op_get_global_var(Instruction* currentInstruction) loadPtr(&globalObject->m_registers, regT2); emitLoad(index, regT1, regT0, regT2); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + OPCODE_LENGTH(op_get_global_var), dst, regT1, regT0); } diff --git a/Source/JavaScriptCore/jit/JITStubCall.h b/Source/JavaScriptCore/jit/JITStubCall.h index 18441c363..51401a77f 100644 --- a/Source/JavaScriptCore/jit/JITStubCall.h +++ b/Source/JavaScriptCore/jit/JITStubCall.h @@ -201,14 +201,14 @@ namespace JSC { return call; } - JIT::Call callWithValueProfiling(unsigned dst, JIT::ValueProfilingSiteKind kind) + JIT::Call callWithValueProfiling(unsigned dst) { ASSERT(m_returnType == Value || m_returnType == Cell); JIT::Call call = this->call(); ASSERT(JIT::returnValueRegister == JIT::regT0); if (m_returnType == Cell) m_jit->move(JIT::TrustedImm32(JSValue::CellTag), JIT::regT1); - m_jit->emitValueProfilingSite(kind); + m_jit->emitValueProfilingSite(); if (m_returnType == Value) m_jit->emitStore(dst, JIT::regT1, JIT::regT0); else @@ -224,12 +224,12 @@ namespace JSC { return call; } - JIT::Call callWithValueProfiling(unsigned dst, JIT::ValueProfilingSiteKind kind) + JIT::Call callWithValueProfiling(unsigned dst) { ASSERT(m_returnType == VoidPtr || m_returnType == Cell); JIT::Call call = this->call(); ASSERT(JIT::returnValueRegister == JIT::regT0); - m_jit->emitValueProfilingSite(kind); + m_jit->emitValueProfilingSite(); m_jit->emitPutVirtualRegister(dst); return call; } diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index 3c16efe01..386d0dfa1 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -37,6 +37,7 @@ #include "Arguments.h" #include "CallFrame.h" #include "CodeBlock.h" +#include "CodeProfiling.h" #include "DFGOSREntry.h" #include "Debugger.h" #include "ExceptionHelpers.h" @@ -101,6 +102,9 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "popl %esi" "\n" "popl %ebp" "\n" "ret" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" ); asm ( @@ -158,6 +162,9 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "popq %r12" "\n" "popq %rbp" "\n" "ret" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" ); asm ( @@ -400,6 +407,9 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "popq %r12" "\n" "popq %rbp" "\n" "ret" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" ); asm ( @@ -560,6 +570,12 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" "bx lr" "\n" +".align 2" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +".thumb" "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" ); asm ( @@ -953,7 +969,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress); } -#ifndef NDEBUG +#if !defined(NDEBUG) extern "C" { @@ -971,7 +987,8 @@ struct StackHack { : stackFrame(stackFrame) , savedReturnAddress(*stackFrame.returnAddressSlot()) { - *stackFrame.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode)); + if (!CodeProfiling::enabled()) + *stackFrame.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode)); } ALWAYS_INLINE ~StackHack() @@ -1303,10 +1320,8 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_add) JSValue v2 = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - if (v1.isString()) { - JSValue result = v2.isString() - ? jsString(callFrame, asString(v1), asString(v2)) - : jsString(callFrame, asString(v1), v2.toPrimitiveString(callFrame)); + if (v1.isString() && !v2.isObject()) { + JSValue result = jsString(callFrame, asString(v1), v2.toString(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -1382,7 +1397,9 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_generic) STUB_INIT_STACK_FRAME(stackFrame); PutPropertySlot slot(stackFrame.callFrame->codeBlock()->isStrictMode()); - stackFrame.args[0].jsValue().putDirect(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot); + JSValue baseValue = stackFrame.args[0].jsValue(); + ASSERT(baseValue.isObject()); + asObject(baseValue)->putDirect(stackFrame.callFrame->globalData(), stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot); CHECK_FOR_EXCEPTION_AT_END(); } @@ -1427,7 +1444,9 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_direct) Identifier& ident = stackFrame.args[1].identifier(); PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); - stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot); + JSValue baseValue = stackFrame.args[0].jsValue(); + ASSERT(baseValue.isObject()); + asObject(baseValue)->putDirect(callFrame->globalData(), ident, stackFrame.args[2].jsValue(), slot); CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); @@ -1460,7 +1479,9 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_fail) Identifier& ident = stackFrame.args[1].identifier(); PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); - stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot); + JSValue baseValue = stackFrame.args[0].jsValue(); + ASSERT(baseValue.isObject()); + asObject(baseValue)->putDirect(callFrame->globalData(), ident, stackFrame.args[2].jsValue(), slot); CHECK_FOR_EXCEPTION_AT_END(); } @@ -1471,7 +1492,8 @@ DEFINE_STUB_FUNCTION(JSObject*, op_put_by_id_transition_realloc) JSValue baseValue = stackFrame.args[0].jsValue(); int32_t oldSize = stackFrame.args[3].int32(); - int32_t newSize = stackFrame.args[4].int32(); + Structure* newStructure = stackFrame.args[4].structure(); + int32_t newSize = newStructure->propertyStorageCapacity(); ASSERT(baseValue.isObject()); JSObject* base = asObject(baseValue); @@ -1909,7 +1931,7 @@ DEFINE_STUB_FUNCTION(void, optimize_from_loop) unsigned bytecodeIndex = stackFrame.args[0].int32(); #if ENABLE(JIT_VERBOSE_OSR) - printf("Entered optimize_from_loop with executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock->executeCounter(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter()); + printf("Entered optimize_from_loop with executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock->jitExecuteCounter(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter()); #endif if (codeBlock->hasOptimizedReplacement()) { @@ -2007,7 +2029,7 @@ DEFINE_STUB_FUNCTION(void, optimize_from_ret) CodeBlock* codeBlock = callFrame->codeBlock(); #if ENABLE(JIT_VERBOSE_OSR) - printf("Entered optimize_from_ret with executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock->executeCounter(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter()); + printf("Entered optimize_from_ret with executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock->jitExecuteCounter(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter()); #endif if (codeBlock->hasOptimizedReplacement()) { @@ -2455,7 +2477,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val) return JSValue::encode(result); } - Identifier property(callFrame, subscript.toString(callFrame)); + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); JSValue result = baseValue.get(callFrame, property); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); @@ -2482,7 +2504,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_string) ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val)); } } else { - Identifier property(callFrame, subscript.toString(callFrame)); + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); result = baseValue.get(callFrame, property); } @@ -2512,7 +2534,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_byte_array) if (!isJSByteArray(baseValue)) ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val)); } else { - Identifier property(callFrame, subscript.toString(callFrame)); + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); result = baseValue.get(callFrame, property); } @@ -2573,7 +2595,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val) } else baseValue.put(callFrame, i, value); } else { - Identifier property(callFrame, subscript.toString(callFrame)); + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception. PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); baseValue.put(callFrame, property, value, slot); @@ -2614,7 +2636,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array) ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val)); baseValue.put(callFrame, i, value); } else { - Identifier property(callFrame, subscript.toString(callFrame)); + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception. PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); baseValue.put(callFrame, property, value, slot); @@ -3380,7 +3402,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_in) if (propName.getUInt32(i)) return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, i))); - Identifier property(callFrame, propName.toString(callFrame)); + Identifier property(callFrame, propName.toString(callFrame)->value(callFrame)); CHECK_FOR_EXCEPTION(); return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, property))); } @@ -3492,7 +3514,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val) result = baseObj->methodTable()->deletePropertyByIndex(baseObj, callFrame, i); else { CHECK_FOR_EXCEPTION(); - Identifier property(callFrame, subscript.toString(callFrame)); + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); CHECK_FOR_EXCEPTION(); result = baseObj->methodTable()->deleteProperty(baseObj, callFrame, property); } @@ -3504,7 +3526,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val) return JSValue::encode(jsBoolean(result)); } -DEFINE_STUB_FUNCTION(void, op_put_getter) +DEFINE_STUB_FUNCTION(void, op_put_getter_setter) { STUB_INIT_STACK_FRAME(stackFrame); @@ -3512,20 +3534,20 @@ DEFINE_STUB_FUNCTION(void, op_put_getter) ASSERT(stackFrame.args[0].jsValue().isObject()); JSObject* baseObj = asObject(stackFrame.args[0].jsValue()); - ASSERT(stackFrame.args[2].jsValue().isObject()); - baseObj->methodTable()->defineGetter(baseObj, callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()), 0); -} -DEFINE_STUB_FUNCTION(void, op_put_setter) -{ - STUB_INIT_STACK_FRAME(stackFrame); + GetterSetter* accessor = GetterSetter::create(callFrame); - CallFrame* callFrame = stackFrame.callFrame; + JSValue getter = stackFrame.args[2].jsValue(); + JSValue setter = stackFrame.args[3].jsValue(); + ASSERT(getter.isObject() || getter.isUndefined()); + ASSERT(setter.isObject() || setter.isUndefined()); + ASSERT(getter.isObject() || setter.isObject()); - ASSERT(stackFrame.args[0].jsValue().isObject()); - JSObject* baseObj = asObject(stackFrame.args[0].jsValue()); - ASSERT(stackFrame.args[2].jsValue().isObject()); - baseObj->methodTable()->defineSetter(baseObj, callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()), 0); + if (!getter.isUndefined()) + accessor->setGetter(callFrame->globalData(), asObject(getter)); + if (!setter.isUndefined()) + accessor->setSetter(callFrame->globalData(), asObject(setter)); + baseObj->putDirectAccessor(callFrame->globalData(), stackFrame.args[1].identifier(), accessor, Accessor); } DEFINE_STUB_FUNCTION(void, op_throw_reference_error) @@ -3533,7 +3555,7 @@ DEFINE_STUB_FUNCTION(void, op_throw_reference_error) STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - UString message = stackFrame.args[0].jsValue().toString(callFrame); + UString message = stackFrame.args[0].jsValue().toString(callFrame)->value(callFrame); stackFrame.globalData->exception = createReferenceError(callFrame, message); VM_THROW_EXCEPTION_AT_END(); } diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h index 241ace968..fe5f522e9 100644 --- a/Source/JavaScriptCore/jit/JITStubs.h +++ b/Source/JavaScriptCore/jit/JITStubs.h @@ -59,6 +59,7 @@ namespace JSC { class PutPropertySlot; class RegisterFile; class RegExp; + class Structure; template <typename T> class Weak; @@ -78,6 +79,7 @@ namespace JSC { JSPropertyNameIterator* propertyNameIterator() { return static_cast<JSPropertyNameIterator*>(asPointer); } JSGlobalObject* globalObject() { return static_cast<JSGlobalObject*>(asPointer); } JSString* jsString() { return static_cast<JSString*>(asPointer); } + Structure* structure() { return static_cast<Structure*>(asPointer); } ReturnAddressPtr returnAddress() { return ReturnAddressPtr(asPointer); } }; @@ -281,6 +283,15 @@ namespace JSC { extern "C" void ctiVMThrowTrampoline(); extern "C" void ctiOpThrowNotCaught(); extern "C" EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*); +#if ENABLE(DFG_JIT) + extern "C" void ctiTrampolineEnd(); + + inline bool returnAddressIsInCtiTrampoline(ReturnAddressPtr returnAddress) + { + return returnAddress.value() >= bitwise_cast<void*>(&ctiTrampoline) + && returnAddress.value() < bitwise_cast<void*>(&ctiTrampolineEnd); + } +#endif class JITThunks { public: @@ -423,8 +434,7 @@ extern "C" { void JIT_STUB cti_op_put_by_index(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_by_val(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_by_val_byte_array(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_getter(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_setter(STUB_ARGS_DECLARATION); + void JIT_STUB cti_op_put_getter_setter(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); diff --git a/Source/JavaScriptCore/jit/SpecializedThunkJIT.h b/Source/JavaScriptCore/jit/SpecializedThunkJIT.h index 1802216fa..74e94ea3c 100644 --- a/Source/JavaScriptCore/jit/SpecializedThunkJIT.h +++ b/Source/JavaScriptCore/jit/SpecializedThunkJIT.h @@ -134,7 +134,7 @@ namespace JSC { MacroAssemblerCodeRef finalize(JSGlobalData& globalData, MacroAssemblerCodePtr fallback) { - LinkBuffer patchBuffer(globalData, this); + LinkBuffer patchBuffer(globalData, this, GLOBAL_THUNK_ID); patchBuffer.link(m_failures, CodeLocationLabel(fallback)); for (unsigned i = 0; i < m_calls.size(); i++) patchBuffer.link(m_calls[i].first, m_calls[i].second); diff --git a/Source/JavaScriptCore/jit/ThunkGenerators.cpp b/Source/JavaScriptCore/jit/ThunkGenerators.cpp index 0e54c8a8f..099796986 100644 --- a/Source/JavaScriptCore/jit/ThunkGenerators.cpp +++ b/Source/JavaScriptCore/jit/ThunkGenerators.cpp @@ -27,8 +27,9 @@ #include "ThunkGenerators.h" #include "CodeBlock.h" -#include <wtf/text/StringImpl.h> +#include "InlineASM.h" #include "SpecializedThunkJIT.h" +#include <wtf/text/StringImpl.h> #if ENABLE(JIT) @@ -111,21 +112,6 @@ MacroAssemblerCodeRef sqrtThunkGenerator(JSGlobalData* globalData) return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); } -#if OS(DARWIN) || (OS(WINDOWS) && CPU(X86)) -#define SYMBOL_STRING(name) "_" #name -#else -#define SYMBOL_STRING(name) #name -#endif - -#if (OS(LINUX) || OS(FREEBSD)) && CPU(X86_64) -#define SYMBOL_STRING_RELOCATION(name) #name "@plt" -#elif OS(DARWIN) || (CPU(X86_64) && COMPILER(MINGW) && !GCC_VERSION_AT_LEAST(4, 5, 0)) -#define SYMBOL_STRING_RELOCATION(name) "_" #name -#elif CPU(X86) && COMPILER(MINGW) -#define SYMBOL_STRING_RELOCATION(name) "@" #name "@4" -#else -#define SYMBOL_STRING_RELOCATION(name) #name -#endif #define UnaryDoubleOpWrapper(function) function##Wrapper enum MathThunkCallingConvention { }; @@ -147,6 +133,7 @@ double jsRound(double d) asm( \ ".text\n" \ ".globl " SYMBOL_STRING(function##Thunk) "\n" \ + HIDE_SYMBOL(function##Thunk) "\n" \ SYMBOL_STRING(function##Thunk) ":" "\n" \ "call " SYMBOL_STRING_RELOCATION(function) "\n" \ "ret\n" \ @@ -161,6 +148,7 @@ double jsRound(double d) asm( \ ".text\n" \ ".globl " SYMBOL_STRING(function##Thunk) "\n" \ + HIDE_SYMBOL(function##Thunk) "\n" \ SYMBOL_STRING(function##Thunk) ":" "\n" \ "subl $8, %esp\n" \ "movsd %xmm0, (%esp) \n" \ diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp index ea32d8976..47ec8c608 100644 --- a/Source/JavaScriptCore/jsc.cpp +++ b/Source/JavaScriptCore/jsc.cpp @@ -238,7 +238,7 @@ EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec) if (i) putchar(' '); - printf("%s", exec->argument(i).toString(exec).utf8().data()); + printf("%s", exec->argument(i).toString(exec)->value(exec).utf8().data()); } putchar('\n'); @@ -248,7 +248,7 @@ EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec) EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec) { - fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec).utf8().data()); + fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data()); return JSValue::encode(jsUndefined()); } @@ -277,7 +277,7 @@ EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*) EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec) { - UString fileName = exec->argument(0).toString(exec); + UString fileName = exec->argument(0).toString(exec)->value(exec); Vector<char> script; if (!fillBufferWithContentsOfFile(fileName, script)) return JSValue::encode(throwError(exec, createError(exec, "Could not open file."))); @@ -294,7 +294,7 @@ EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec) EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec) { - UString fileName = exec->argument(0).toString(exec); + UString fileName = exec->argument(0).toString(exec)->value(exec); Vector<char> script; if (!fillBufferWithContentsOfFile(fileName, script)) return JSValue::encode(throwError(exec, createError(exec, "Could not open file."))); @@ -310,7 +310,7 @@ EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec) EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec) { - UString fileName = exec->argument(0).toString(exec); + UString fileName = exec->argument(0).toString(exec)->value(exec); Vector<char> script; if (!fillBufferWithContentsOfFile(fileName, script)) return JSValue::encode(throwError(exec, createError(exec, "Could not open file."))); @@ -487,9 +487,9 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scr success = success && !evaluationException; if (dump) { if (evaluationException) - printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec()).utf8().data()); + printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data()); else - printf("End: %s\n", returnValue.toString(globalObject->globalExec()).utf8().data()); + printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data()); } globalData.stopSampling(); @@ -546,9 +546,9 @@ static void runInteractive(GlobalObject* globalObject) JSValue returnValue = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException); #endif if (evaluationException) - printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec()).utf8().data()); + printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data()); else - printf("%s\n", returnValue.toString(globalObject->globalExec()).utf8().data()); + printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data()); globalObject->globalExec()->clearException(); } diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h index 2e81c2546..b6ea004b5 100644 --- a/Source/JavaScriptCore/parser/ASTBuilder.h +++ b/Source/JavaScriptCore/parser/ASTBuilder.h @@ -249,6 +249,8 @@ public: ExpressionNode* createAssignResolve(int lineNumber, const Identifier& ident, ExpressionNode* rhs, bool rhsHasAssignment, int start, int divot, int end) { + if (rhs->isFuncExprNode()) + static_cast<FuncExprNode*>(rhs)->body()->setInferredName(ident); AssignResolveNode* node = new (m_globalData) AssignResolveNode(lineNumber, ident, rhs, rhsHasAssignment); setExceptionLocation(node, start, divot, end); return node; @@ -271,6 +273,7 @@ public: { ASSERT(name); body->setLoc(bodyStartLine, bodyEndLine); + body->setInferredName(*name); return new (m_globalData) PropertyNode(m_globalData, *name, new (m_globalData) FuncExprNode(lineNumber, m_globalData->propertyNames->nullIdentifier, body, m_sourceCode->subExpression(openBracePos, closeBracePos, bodyStartLine), params), type); } @@ -280,7 +283,12 @@ public: ArgumentListNode* createArgumentsList(int lineNumber, ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(lineNumber, arg); } ArgumentListNode* createArgumentsList(int lineNumber, ArgumentListNode* args, ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(lineNumber, args, arg); } - template <bool> PropertyNode* createProperty(const Identifier* propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, *propertyName, node, type); } + template <bool> PropertyNode* createProperty(const Identifier* propertyName, ExpressionNode* node, PropertyNode::Type type) + { + if (node->isFuncExprNode()) + static_cast<FuncExprNode*>(node)->body()->setInferredName(*propertyName); + return new (m_globalData) PropertyNode(m_globalData, *propertyName, node, type); + } template <bool> PropertyNode* createProperty(JSGlobalData*, double propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, propertyName, node, type); } PropertyListNode* createPropertyList(int lineNumber, PropertyNode* property) { return new (m_globalData) PropertyListNode(lineNumber, property); } PropertyListNode* createPropertyList(int lineNumber, PropertyNode* property, PropertyListNode* tail) { return new (m_globalData) PropertyListNode(lineNumber, property, tail); } @@ -411,9 +419,9 @@ public: return result; } - StatementNode* createTryStatement(int lineNumber, StatementNode* tryBlock, const Identifier* ident, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine) + StatementNode* createTryStatement(int lineNumber, StatementNode* tryBlock, const Identifier* ident, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine) { - TryNode* result = new (m_globalData) TryNode(lineNumber, tryBlock, *ident, catchHasEval, catchBlock, finallyBlock); + TryNode* result = new (m_globalData) TryNode(lineNumber, tryBlock, *ident, catchBlock, finallyBlock); if (catchBlock) usesCatch(); result->setLoc(startLine, endLine); @@ -903,6 +911,8 @@ ExpressionNode* ASTBuilder::makeAssignNode(int lineNumber, ExpressionNode* loc, if (loc->isResolveNode()) { ResolveNode* resolve = static_cast<ResolveNode*>(loc); if (op == OpEqual) { + if (expr->isFuncExprNode()) + static_cast<FuncExprNode*>(expr)->body()->setInferredName(resolve->identifier()); AssignResolveNode* node = new (m_globalData) AssignResolveNode(lineNumber, resolve->identifier(), expr, exprHasAssignments); setExceptionLocation(node, start, divot, end); return node; @@ -919,8 +929,11 @@ ExpressionNode* ASTBuilder::makeAssignNode(int lineNumber, ExpressionNode* loc, } ASSERT(loc->isDotAccessorNode()); DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc); - if (op == OpEqual) + if (op == OpEqual) { + if (expr->isFuncExprNode()) + static_cast<FuncExprNode*>(expr)->body()->setInferredName(dot->identifier()); return new (m_globalData) AssignDotNode(lineNumber, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot()); + } ReadModifyDotNode* node = new (m_globalData) ReadModifyDotNode(lineNumber, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot); node->setSubexpressionInfo(dot->divot(), dot->endOffset()); diff --git a/Source/JavaScriptCore/parser/Keywords.table b/Source/JavaScriptCore/parser/Keywords.table index fab0e23cc..333b4762d 100644 --- a/Source/JavaScriptCore/parser/Keywords.table +++ b/Source/JavaScriptCore/parser/Keywords.table @@ -43,10 +43,12 @@ extends RESERVED import RESERVED super RESERVED +# technically RESERVED_IF_STRICT in ES5, but may be reserved in ES6. +let RESERVED + # reserved for future use in strict code implements RESERVED_IF_STRICT interface RESERVED_IF_STRICT -let RESERVED_IF_STRICT package RESERVED_IF_STRICT private RESERVED_IF_STRICT protected RESERVED_IF_STRICT diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h index 6c069490d..eea3f575c 100644 --- a/Source/JavaScriptCore/parser/NodeConstructors.h +++ b/Source/JavaScriptCore/parser/NodeConstructors.h @@ -781,13 +781,12 @@ namespace JSC { { } - inline TryNode::TryNode(int lineNumber, StatementNode* tryBlock, const Identifier& exceptionIdent, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock) + inline TryNode::TryNode(int lineNumber, StatementNode* tryBlock, const Identifier& exceptionIdent, StatementNode* catchBlock, StatementNode* finallyBlock) : StatementNode(lineNumber) , m_tryBlock(tryBlock) , m_exceptionIdent(exceptionIdent) , m_catchBlock(catchBlock) , m_finallyBlock(finallyBlock) - , m_catchHasEval(catchHasEval) { } diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h index 23f2cde9c..278d17ef4 100644 --- a/Source/JavaScriptCore/parser/Nodes.h +++ b/Source/JavaScriptCore/parser/Nodes.h @@ -181,7 +181,7 @@ namespace JSC { StatementNode(int); public: - void setLoc(int firstLine, int lastLine); + JS_EXPORT_PRIVATE void setLoc(int firstLine, int lastLine); int firstLine() const { return lineNo(); } int lastLine() const { return m_lastLine; } @@ -1348,7 +1348,7 @@ namespace JSC { class TryNode : public StatementNode { public: - TryNode(int, StatementNode* tryBlock, const Identifier& exceptionIdent, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock); + TryNode(int, StatementNode* tryBlock, const Identifier& exceptionIdent, StatementNode* catchBlock, StatementNode* finallyBlock); private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); @@ -1357,7 +1357,6 @@ namespace JSC { const Identifier& m_exceptionIdent; StatementNode* m_catchBlock; StatementNode* m_finallyBlock; - bool m_catchHasEval; }; class ParameterNode : public ParserArenaFreeable { @@ -1494,6 +1493,8 @@ namespace JSC { void finishParsing(PassRefPtr<FunctionParameters>, const Identifier&); const Identifier& ident() { return m_ident; } + void setInferredName(const Identifier& inferredName) { m_inferredName = inferredName; } + const Identifier& inferredName() { return m_inferredName.isEmpty() ? m_ident : m_inferredName; } static const bool scopeIsFunction = true; @@ -1502,6 +1503,7 @@ namespace JSC { FunctionBodyNode(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants); Identifier m_ident; + Identifier m_inferredName; RefPtr<FunctionParameters> m_parameters; }; diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp index 5c2f0383f..ce6519873 100644 --- a/Source/JavaScriptCore/parser/Parser.cpp +++ b/Source/JavaScriptCore/parser/Parser.cpp @@ -43,7 +43,7 @@ template <typename LexerType> Parser<LexerType>::Parser(JSGlobalData* globalData, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode) : m_globalData(globalData) , m_source(&source) - , m_stack(globalData->stack()) + , m_stack(wtfThreadData().stack()) , m_error(false) , m_errorMessage("Parse error") , m_allowsIn(true) @@ -603,7 +603,6 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseTryStatement( ASSERT(match(TRY)); TreeStatement tryBlock = 0; const Identifier* ident = &m_globalData->propertyNames->nullIdentifier; - bool catchHasEval = false; TreeStatement catchBlock = 0; TreeStatement finallyBlock = 0; int firstLine = tokenLine(); @@ -626,10 +625,8 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseTryStatement( catchScope->preventNewDecls(); consumeOrFail(CLOSEPAREN); matchOrFail(OPENBRACE); - int initialEvalCount = context.evalCount(); catchBlock = parseBlockStatement(context); failIfFalseWithMessage(catchBlock, "'try' must have a catch or finally block"); - catchHasEval = initialEvalCount != context.evalCount(); failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo)); } @@ -640,7 +637,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseTryStatement( failIfFalse(finallyBlock); } failIfFalse(catchBlock || finallyBlock); - return context.createTryStatement(m_lexer->lastLineNumber(), tryBlock, ident, catchHasEval, catchBlock, finallyBlock, firstLine, lastLine); + return context.createTryStatement(m_lexer->lastLineNumber(), tryBlock, ident, catchBlock, finallyBlock, firstLine, lastLine); } template <typename LexerType> @@ -1512,23 +1509,20 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres } case OPENPAREN: { m_nonTrivialExpressionCount++; + int nonLHSCount = m_nonLHSCount; if (newCount) { newCount--; - if (match(OPENPAREN)) { - int exprEnd = lastTokenEnd(); - TreeArguments arguments = parseArguments(context); - failIfFalse(arguments); - base = context.createNewExpr(m_lexer->lastLineNumber(), base, arguments, start, exprEnd, lastTokenEnd()); - } else - base = context.createNewExpr(m_lexer->lastLineNumber(), base, start, lastTokenEnd()); + int exprEnd = lastTokenEnd(); + TreeArguments arguments = parseArguments(context); + failIfFalse(arguments); + base = context.createNewExpr(m_lexer->lastLineNumber(), base, arguments, start, exprEnd, lastTokenEnd()); } else { - int nonLHSCount = m_nonLHSCount; int expressionEnd = lastTokenEnd(); TreeArguments arguments = parseArguments(context); failIfFalse(arguments); base = context.makeFunctionCallNode(m_lexer->lastLineNumber(), base, arguments, expressionStart, expressionEnd, lastTokenEnd()); - m_nonLHSCount = nonLHSCount; } + m_nonLHSCount = nonLHSCount; break; } case DOT: { diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h index ef176f014..f3d96ff3e 100644 --- a/Source/JavaScriptCore/parser/Parser.h +++ b/Source/JavaScriptCore/parser/Parser.h @@ -559,7 +559,7 @@ private: case CASE: return "case"; case DEFAULT: - return "defualt"; + return "default"; case FOR: return "for"; case NEW: diff --git a/Source/JavaScriptCore/parser/ParserArena.h b/Source/JavaScriptCore/parser/ParserArena.h index 35674b604..49f0ab6bf 100644 --- a/Source/JavaScriptCore/parser/ParserArena.h +++ b/Source/JavaScriptCore/parser/ParserArena.h @@ -159,7 +159,7 @@ namespace JSC { void removeLast(); bool isEmpty() const; - void reset(); + JS_EXPORT_PRIVATE void reset(); IdentifierArena& identifierArena() { return *m_identifierArena; } diff --git a/Source/JavaScriptCore/parser/SyntaxChecker.h b/Source/JavaScriptCore/parser/SyntaxChecker.h index 270c82385..32cbf7d6c 100644 --- a/Source/JavaScriptCore/parser/SyntaxChecker.h +++ b/Source/JavaScriptCore/parser/SyntaxChecker.h @@ -193,7 +193,7 @@ public: int createBreakStatement(int, const Identifier*, int, int, int, int) { return 1; } int createContinueStatement(int, int, int, int, int) { return 1; } int createContinueStatement(int, const Identifier*, int, int, int, int) { return 1; } - int createTryStatement(int, int, const Identifier*, bool, int, int, int, int) { return 1; } + int createTryStatement(int, int, const Identifier*, int, int, int, int) { return 1; } int createSwitchStatement(int, int, int, int, int, int, int) { return 1; } int createWhileStatement(int, int, int, int, int) { return 1; } int createWithStatement(int, int, int, int, int, int, int) { return 1; } diff --git a/Source/JavaScriptCore/profiler/Profile.h b/Source/JavaScriptCore/profiler/Profile.h index 6bf29f7a6..9455e3595 100644 --- a/Source/JavaScriptCore/profiler/Profile.h +++ b/Source/JavaScriptCore/profiler/Profile.h @@ -44,11 +44,11 @@ namespace JSC { double totalTime() const { return m_head->totalTime(); } unsigned int uid() const { return m_uid; } - void forEach(void (ProfileNode::*)()); + JS_EXPORT_PRIVATE void forEach(void (ProfileNode::*)()); - void focus(const ProfileNode*); - void exclude(const ProfileNode*); - void restoreAll(); + JS_EXPORT_PRIVATE void focus(const ProfileNode*); + JS_EXPORT_PRIVATE void exclude(const ProfileNode*); + JS_EXPORT_PRIVATE void restoreAll(); #ifndef NDEBUG void debugPrintData() const; diff --git a/Source/JavaScriptCore/profiler/Profiler.cpp b/Source/JavaScriptCore/profiler/Profiler.cpp index 0a4b547d4..0ecd5b2c9 100644 --- a/Source/JavaScriptCore/profiler/Profiler.cpp +++ b/Source/JavaScriptCore/profiler/Profiler.cpp @@ -48,7 +48,7 @@ static const char* GlobalCodeExecution = "(program)"; static const char* AnonymousFunction = "(anonymous function)"; static unsigned ProfilesUID = 0; -static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSFunction*); +static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSObject*, const UString& defaultSourceURL, int defaultLineNumber); Profiler* Profiler::s_sharedProfiler = 0; Profiler* Profiler::s_sharedEnabledProfilerReference = 0; @@ -163,23 +163,18 @@ CallIdentifier Profiler::createCallIdentifier(ExecState* exec, JSValue functionV return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber); if (!functionValue.isObject()) return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber); - if (asObject(functionValue)->inherits(&JSFunction::s_info)) { - JSFunction* function = asFunction(functionValue); - if (!function->executable()->isHostFunction()) - return createCallIdentifierFromFunctionImp(exec, function); - } - if (asObject(functionValue)->inherits(&JSFunction::s_info)) - return CallIdentifier(static_cast<JSFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber); - if (asObject(functionValue)->inherits(&InternalFunction::s_info)) - return CallIdentifier(static_cast<InternalFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber); + if (asObject(functionValue)->inherits(&JSFunction::s_info) || asObject(functionValue)->inherits(&InternalFunction::s_info)) + return createCallIdentifierFromFunctionImp(exec, asObject(functionValue), defaultSourceURL, defaultLineNumber); return CallIdentifier(makeUString("(", asObject(functionValue)->methodTable()->className(asObject(functionValue)), " object)"), defaultSourceURL, defaultLineNumber); } -CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSFunction* function) +CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSObject* function, const UString& defaultSourceURL, int defaultLineNumber) { - ASSERT(!function->isHostFunction()); - const UString& name = function->calculatedDisplayName(exec); - return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, function->jsExecutable()->sourceURL(), function->jsExecutable()->lineNo()); + const UString& name = getCalculatedDisplayName(exec, function); + JSFunction* jsFunction = jsDynamicCast<JSFunction*>(function); + if (jsFunction && !jsFunction->isHostFunction()) + return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, jsFunction->jsExecutable()->sourceURL(), jsFunction->jsExecutable()->lineNo()); + return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, defaultSourceURL, defaultLineNumber); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArgList.h b/Source/JavaScriptCore/runtime/ArgList.h index ac5a4f271..1512a0fa1 100644 --- a/Source/JavaScriptCore/runtime/ArgList.h +++ b/Source/JavaScriptCore/runtime/ArgList.h @@ -102,7 +102,7 @@ namespace JSC { static void markLists(HeapRootVisitor&, ListSet&); private: - void slowAppend(JSValue); + JS_EXPORT_PRIVATE void slowAppend(JSValue); EncodedJSValue& slotFor(int item) const { @@ -171,7 +171,7 @@ namespace JSC { bool isEmpty() const { return !m_argCount; } size_t size() const { return m_argCount; } - void getSlice(int startIndex, ArgList& result) const; + JS_EXPORT_PRIVATE void getSlice(int startIndex, ArgList& result) const; private: JSValue* m_args; diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp index fc136eb7e..6a675ab84 100644 --- a/Source/JavaScriptCore/runtime/Arguments.cpp +++ b/Source/JavaScriptCore/runtime/Arguments.cpp @@ -109,7 +109,7 @@ void Arguments::createStrictModeCallerIfNecessary(ExecState* exec) d->overrodeCaller = true; PropertyDescriptor descriptor; - descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec), DontEnum | DontDelete | Getter | Setter); + descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec), DontEnum | DontDelete | Accessor); methodTable()->defineOwnProperty(this, exec, exec->propertyNames().caller, descriptor, false); } @@ -120,7 +120,7 @@ void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec) d->overrodeCallee = true; PropertyDescriptor descriptor; - descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec), DontEnum | DontDelete | Getter | Setter); + descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec), DontEnum | DontDelete | Accessor); methodTable()->defineOwnProperty(this, exec, exec->propertyNames().callee, descriptor, false); } diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index dcf7a2fae..cb9b12a59 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -197,7 +197,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec) if (element.isUndefinedOrNull()) continue; - UString str = element.toString(exec); + UString str = element.toString(exec)->value(exec); strBuffer[k] = str.impl(); totalSize += str.length(); allStrings8Bit = allStrings8Bit && str.is8Bit(); @@ -272,9 +272,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec) CallData callData; CallType callType = getCallData(conversionFunction, callData); if (callType != CallTypeNone) - str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toString(exec); + str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toString(exec)->value(exec); else - str = element.toString(exec); + str = element.toString(exec)->value(exec); strBuffer.append(str); } } @@ -297,7 +297,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) UString separator; if (!exec->argument(0).isUndefined()) - separator = exec->argument(0).toString(exec); + separator = exec->argument(0).toString(exec)->value(exec); unsigned k = 0; if (isJSArray(thisObj)) { @@ -308,7 +308,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) goto skipFirstLoop; JSValue element = array->getIndex(k); if (!element.isUndefinedOrNull()) - strBuffer.append(element.toString(exec)); + strBuffer.append(element.toString(exec)->value(exec)); k++; } @@ -319,7 +319,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) strBuffer.append(','); JSValue element = array->getIndex(k); if (!element.isUndefinedOrNull()) - strBuffer.append(element.toString(exec)); + strBuffer.append(element.toString(exec)->value(exec)); } } else { for (; k < length; k++) { @@ -328,7 +328,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) strBuffer.append(separator); JSValue element = array->getIndex(k); if (!element.isUndefinedOrNull()) - strBuffer.append(element.toString(exec)); + strBuffer.append(element.toString(exec)->value(exec)); } } } @@ -343,7 +343,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) JSValue element = thisObj->get(exec, k); if (!element.isUndefinedOrNull()) - strBuffer.append(element.toString(exec)); + strBuffer.append(element.toString(exec)->value(exec)); } return JSValue::encode(strBuffer.build(exec)); @@ -429,7 +429,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec) thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->argument(n)); else { PutPropertySlot slot; - Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toString(exec)); + Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toString(exec)->value(exec)); thisObj->methodTable()->put(thisObj, exec, propertyName, exec->argument(n), slot); } } @@ -571,7 +571,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) l.append(minObj); compareResult = call(exec, function, callType, callData, jsUndefined(), l).toNumber(exec); } else - compareResult = (jObj.toString(exec) < minObj.toString(exec)) ? -1 : 1; + compareResult = (jObj.toString(exec)->value(exec) < minObj.toString(exec)->value(exec)) ? -1 : 1; if (compareResult < 0) { themin = j; diff --git a/Source/JavaScriptCore/runtime/CallData.h b/Source/JavaScriptCore/runtime/CallData.h index b138f5484..15a6a0a48 100644 --- a/Source/JavaScriptCore/runtime/CallData.h +++ b/Source/JavaScriptCore/runtime/CallData.h @@ -57,7 +57,7 @@ namespace JSC { } js; }; - JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&); + JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h index 9fff64e67..3d556d88c 100644 --- a/Source/JavaScriptCore/runtime/ClassInfo.h +++ b/Source/JavaScriptCore/runtime/ClassInfo.h @@ -88,7 +88,7 @@ namespace JSC { HasInstanceFunctionPtr hasInstance; typedef void (*PutWithAttributesFunctionPtr)(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); - PutWithAttributesFunctionPtr putWithAttributes; + PutWithAttributesFunctionPtr putDirectVirtual; typedef bool (*DefineOwnPropertyFunctionPtr)(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&, bool); DefineOwnPropertyFunctionPtr defineOwnProperty; @@ -135,7 +135,7 @@ struct MemberCheck##member { \ &ClassName::getPropertyNames, \ &ClassName::className, \ &ClassName::hasInstance, \ - &ClassName::putWithAttributes, \ + &ClassName::putDirectVirtual, \ &ClassName::defineOwnProperty, \ &ClassName::getOwnPropertyDescriptor, \ }, \ diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h index ab4de7da8..86c4bd5c2 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h +++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h @@ -76,7 +76,7 @@ inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal) if (propName.getUInt32(i)) return baseObj->hasProperty(exec, i); - Identifier property(exec, propName.toString(exec)); + Identifier property(exec, propName.toString(exec)->value(exec)); if (exec->globalData().exception) return false; return baseObj->hasProperty(exec, property); diff --git a/Source/JavaScriptCore/runtime/Completion.cpp b/Source/JavaScriptCore/runtime/Completion.cpp index c3d9e6947..98a66589a 100644 --- a/Source/JavaScriptCore/runtime/Completion.cpp +++ b/Source/JavaScriptCore/runtime/Completion.cpp @@ -24,6 +24,7 @@ #include "Completion.h" #include "CallFrame.h" +#include "CodeProfiling.h" #include "JSGlobalObject.h" #include "JSLock.h" #include "Interpreter.h" @@ -55,6 +56,8 @@ JSValue evaluate(ExecState* exec, ScopeChainNode* scopeChain, const SourceCode& JSLock lock(exec); ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable()); + CodeProfiling profile(source); + ProgramExecutable* program = ProgramExecutable::create(exec, source); if (!program) { if (returnedException) diff --git a/Source/JavaScriptCore/runtime/Completion.h b/Source/JavaScriptCore/runtime/Completion.h index c3dbdfc58..3d3b86fe4 100644 --- a/Source/JavaScriptCore/runtime/Completion.h +++ b/Source/JavaScriptCore/runtime/Completion.h @@ -31,8 +31,8 @@ namespace JSC { class ScopeChainNode; class SourceCode; - bool checkSyntax(ExecState*, const SourceCode&, JSValue* exception = 0); - JSValue evaluate(ExecState*, ScopeChainNode*, const SourceCode&, JSValue thisValue = JSValue(), JSValue* exception = 0); + JS_EXPORT_PRIVATE bool checkSyntax(ExecState*, const SourceCode&, JSValue* exception = 0); + JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, ScopeChainNode*, const SourceCode&, JSValue thisValue = JSValue(), JSValue* exception = 0); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ConstructData.h b/Source/JavaScriptCore/runtime/ConstructData.h index cc8f46977..d7a3c73d3 100644 --- a/Source/JavaScriptCore/runtime/ConstructData.h +++ b/Source/JavaScriptCore/runtime/ConstructData.h @@ -56,7 +56,7 @@ namespace JSC { } js; }; - JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&); + JS_EXPORT_PRIVATE JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp index 79c5181eb..365172294 100644 --- a/Source/JavaScriptCore/runtime/DateConstructor.cpp +++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp @@ -185,7 +185,7 @@ CallType DateConstructor::getCallData(JSCell*, CallData& callData) static EncodedJSValue JSC_HOST_CALL dateParse(ExecState* exec) { - return JSValue::encode(jsNumber(parseDate(exec, exec->argument(0).toString(exec)))); + return JSValue::encode(jsNumber(parseDate(exec, exec->argument(0).toString(exec)->value(exec)))); } static EncodedJSValue JSC_HOST_CALL dateNow(ExecState*) diff --git a/Source/JavaScriptCore/runtime/DateInstance.h b/Source/JavaScriptCore/runtime/DateInstance.h index 3edfb0970..7c976a514 100644 --- a/Source/JavaScriptCore/runtime/DateInstance.h +++ b/Source/JavaScriptCore/runtime/DateInstance.h @@ -31,9 +31,9 @@ namespace JSC { class DateInstance : public JSWrapperObject { protected: - DateInstance(ExecState*, Structure*); + JS_EXPORT_PRIVATE DateInstance(ExecState*, Structure*); void finishCreation(JSGlobalData&); - void finishCreation(JSGlobalData&, double); + JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&, double); static void destroy(JSCell*); diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp index 96dea01db..922fb0a86 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.cpp +++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp @@ -60,8 +60,10 @@ #include <sys/timeb.h> #endif -#if PLATFORM(MAC) || PLATFORM(IOS) +#if PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(WX) || (PLATFORM(QT) && OS(DARWIN)) #include <CoreFoundation/CoreFoundation.h> +#elif USE(ICU_UNICODE) +#include <unicode/udat.h> #endif #if OS(WINCE) && !PLATFORM(QT) @@ -128,7 +130,7 @@ namespace JSC { enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime }; -#if PLATFORM(MAC) || PLATFORM(IOS) +#if PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(WX) || (PLATFORM(QT) && OS(DARWIN)) // FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)? // Instead we should consider using this whenever USE(CF) is true. @@ -154,13 +156,13 @@ static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMil bool useCustomFormat = false; UString customFormatString; - UString arg0String = exec->argument(0).toString(exec); + UString arg0String = exec->argument(0).toString(exec)->value(exec); if (arg0String == "custom" && !exec->argument(1).isUndefined()) { useCustomFormat = true; - customFormatString = exec->argument(1).toString(exec); + customFormatString = exec->argument(1).toString(exec)->value(exec); } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) { dateStyle = styleFromArgString(arg0String, dateStyle); - timeStyle = styleFromArgString(exec->argument(1).toString(exec), timeStyle); + timeStyle = styleFromArgString(exec->argument(1).toString(exec)->value(exec), timeStyle); } else if (format != LocaleTime && !exec->argument(0).isUndefined()) dateStyle = styleFromArgString(arg0String, dateStyle); else if (format != LocaleDate && !exec->argument(0).isUndefined()) @@ -195,7 +197,29 @@ static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMil return jsNontrivialString(exec, UString(buffer, length)); } -#else // !PLATFORM(MAC) && !PLATFORM(IOS) +#elif USE(ICU_UNICODE) && !UCONFIG_NO_FORMATTING + +static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double timeInMilliseconds, LocaleDateTimeFormat format) +{ + UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE); + UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE); + + UErrorCode status = U_ZERO_ERROR; + UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status); + if (!df) + return jsEmptyString(exec); + + UChar buffer[128]; + int32_t length; + length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status); + udat_close(df); + if (status != U_ZERO_ERROR) + return jsEmptyString(exec); + + return jsNontrivialString(exec, UString(buffer, length)); +} + +#else static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format) { diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp index 24f5da4f2..0947e3c20 100644 --- a/Source/JavaScriptCore/runtime/Error.cpp +++ b/Source/JavaScriptCore/runtime/Error.cpp @@ -37,7 +37,6 @@ namespace JSC { static const char* linePropertyName = "line"; -static const char* sourceIdPropertyName = "sourceId"; static const char* sourceURLPropertyName = "sourceURL"; JSObject* createError(JSGlobalObject* globalObject, const UString& message) @@ -119,15 +118,12 @@ JSObject* createURIError(ExecState* exec, const UString& message) JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source) { - intptr_t sourceID = source.provider()->asID(); const UString& sourceURL = source.provider()->url(); if (line != -1) - error->putWithAttributes(globalData, Identifier(globalData, linePropertyName), jsNumber(line), ReadOnly | DontDelete); - if (sourceID != -1) - error->putWithAttributes(globalData, Identifier(globalData, sourceIdPropertyName), jsNumber((double)sourceID), ReadOnly | DontDelete); + error->putDirect(*globalData, Identifier(globalData, linePropertyName), jsNumber(line), ReadOnly | DontDelete); if (!sourceURL.isNull()) - error->putWithAttributes(globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete); + error->putDirect(*globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete); return error; } @@ -140,7 +136,6 @@ JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceC 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)); } diff --git a/Source/JavaScriptCore/runtime/Error.h b/Source/JavaScriptCore/runtime/Error.h index b807d4ab4..88b540a35 100644 --- a/Source/JavaScriptCore/runtime/Error.h +++ b/Source/JavaScriptCore/runtime/Error.h @@ -46,12 +46,12 @@ namespace JSC { JSObject* createTypeError(JSGlobalObject*, const UString&); JSObject* createURIError(JSGlobalObject*, const UString&); // ExecState wrappers. - JSObject* createError(ExecState*, const UString&); + JS_EXPORT_PRIVATE JSObject* createError(ExecState*, const UString&); JSObject* createEvalError(ExecState*, const UString&); - JSObject* createRangeError(ExecState*, const UString&); - JSObject* createReferenceError(ExecState*, const UString&); - JSObject* createSyntaxError(ExecState*, const UString&); - JSObject* createTypeError(ExecState*, const UString&); + JS_EXPORT_PRIVATE JSObject* createRangeError(ExecState*, const UString&); + JS_EXPORT_PRIVATE JSObject* createReferenceError(ExecState*, const UString&); + JS_EXPORT_PRIVATE JSObject* createSyntaxError(ExecState*, const UString&); + JS_EXPORT_PRIVATE JSObject* createTypeError(ExecState*, const UString&); JSObject* createURIError(ExecState*, const UString&); // Methods to add @@ -61,12 +61,12 @@ namespace JSC { JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&); // Methods to throw Errors. - JSValue throwError(ExecState*, JSValue); - JSObject* throwError(ExecState*, JSObject*); + JS_EXPORT_PRIVATE JSValue throwError(ExecState*, JSValue); + JS_EXPORT_PRIVATE JSObject* throwError(ExecState*, JSObject*); // Convenience wrappers, create an throw an exception with a default message. - JSObject* throwTypeError(ExecState*); - JSObject* throwSyntaxError(ExecState*); + JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*); + JS_EXPORT_PRIVATE JSObject* throwSyntaxError(ExecState*); // Convenience wrappers, wrap result as an EncodedJSValue. inline EncodedJSValue throwVMError(ExecState* exec, JSValue error) { return JSValue::encode(throwError(exec, error)); } diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.h b/Source/JavaScriptCore/runtime/ErrorInstance.h index 888bfe856..d6fa32f99 100644 --- a/Source/JavaScriptCore/runtime/ErrorInstance.h +++ b/Source/JavaScriptCore/runtime/ErrorInstance.h @@ -42,14 +42,10 @@ namespace JSC { instance->finishCreation(globalData, message); return instance; } + static ErrorInstance* create(ExecState* exec, Structure* structure, JSValue message) { - if (message.isUndefined()) { - ErrorInstance* instance = new (NotNull, allocateCell<ErrorInstance>(*exec->heap())) ErrorInstance(exec->globalData(), structure); - instance->finishCreation(exec->globalData(), UString()); - return instance; - } - return create(exec->globalData(), structure, message.toString(exec)); + return create(exec->globalData(), structure, message.isUndefined() ? UString() : message.toString(exec)->value(exec)); } bool appendSourceToMessage() { return m_appendSourceToMessage; } diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp index e1a395c0e..7af294782 100644 --- a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -101,7 +101,7 @@ EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec) if (name.isUndefined()) nameString = "Error"; else { - nameString = name.toString(exec); + nameString = name.toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); } @@ -118,7 +118,7 @@ EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec) if (message.isUndefined()) messageString = ""; else { - messageString = message.toString(exec); + messageString = message.toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); } diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp index 05e971f7f..ce63ae9af 100644 --- a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -113,7 +113,7 @@ JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident) JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value) { - UString errorMessage = makeUString("'", value.toString(exec), "' is not a valid argument for '", op, "'"); + UString errorMessage = makeUString("'", value.toString(exec)->value(exec), "' is not a valid argument for '", op, "'"); JSObject* exception = createTypeError(exec, errorMessage); ASSERT(exception->isErrorInstance()); static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); @@ -122,7 +122,7 @@ JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value JSObject* createNotAConstructorError(ExecState* exec, JSValue value) { - UString errorMessage = makeUString("'", value.toString(exec), "' is not a constructor"); + UString errorMessage = makeUString("'", value.toString(exec)->value(exec), "' is not a constructor"); JSObject* exception = createTypeError(exec, errorMessage); ASSERT(exception->isErrorInstance()); static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); @@ -131,7 +131,7 @@ JSObject* createNotAConstructorError(ExecState* exec, JSValue value) JSObject* createNotAFunctionError(ExecState* exec, JSValue value) { - UString errorMessage = makeUString("'", value.toString(exec), "' is not a function"); + UString errorMessage = makeUString("'", value.toString(exec)->value(exec), "' is not a function"); JSObject* exception = createTypeError(exec, errorMessage); ASSERT(exception->isErrorInstance()); static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); @@ -140,7 +140,7 @@ JSObject* createNotAFunctionError(ExecState* exec, JSValue value) JSObject* createNotAnObjectError(ExecState* exec, JSValue value) { - UString errorMessage = makeUString("'", value.toString(exec), "' is not an object"); + UString errorMessage = makeUString("'", value.toString(exec)->value(exec), "' is not an object"); JSObject* exception = createTypeError(exec, errorMessage); ASSERT(exception->isErrorInstance()); static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.h b/Source/JavaScriptCore/runtime/ExceptionHelpers.h index f71d1a308..7bffd294b 100644 --- a/Source/JavaScriptCore/runtime/ExceptionHelpers.h +++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.h @@ -33,15 +33,15 @@ namespace JSC { -JSObject* createInterruptedExecutionException(JSGlobalData*); +JS_EXPORT_PRIVATE JSObject* createInterruptedExecutionException(JSGlobalData*); bool isInterruptedExecutionException(JSObject*); bool isInterruptedExecutionException(JSValue); JSObject* createTerminatedExecutionException(JSGlobalData*); bool isTerminatedExecutionException(JSObject*); -bool isTerminatedExecutionException(JSValue); +JS_EXPORT_PRIVATE bool isTerminatedExecutionException(JSValue); -JSObject* createStackOverflowError(ExecState*); +JS_EXPORT_PRIVATE JSObject* createStackOverflowError(ExecState*); JSObject* createStackOverflowError(JSGlobalObject*); JSObject* createOutOfMemoryError(JSGlobalObject*); JSObject* createUndefinedVariableError(ExecState*, const Identifier&); @@ -79,7 +79,7 @@ public: return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } - static JS_EXPORTDATA const ClassInfo s_info; + static const ClassInfo s_info; }; class TerminatedExecutionError : public JSNonFinalObject { diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index a364e84da..c67c54cd2 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -30,6 +30,7 @@ #include "CodeBlock.h" #include "DFGDriver.h" #include "JIT.h" +#include "JITDriver.h" #include "Parser.h" #include "UStringBuilder.h" #include "Vector.h" @@ -130,22 +131,24 @@ void ProgramExecutable::destroy(JSCell* cell) const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; -FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext) +FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext) : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, source, inStrictContext) , m_numCapturedVariables(0) , m_forceUsesArguments(forceUsesArguments) , m_parameters(parameters) , m_name(name) + , m_inferredName(inferredName) , m_symbolTable(0) { } -FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext) +FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext) : ScriptExecutable(exec->globalData().functionExecutableStructure.get(), exec, source, inStrictContext) , m_numCapturedVariables(0) , m_forceUsesArguments(forceUsesArguments) , m_parameters(parameters) , m_name(name) + , m_inferredName(inferredName) , m_symbolTable(0) { } @@ -209,27 +212,8 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope } #if ENABLE(JIT) - if (exec->globalData().canUseJIT()) { - bool dfgCompiled = false; - if (jitType == JITCode::DFGJIT) - dfgCompiled = DFG::tryCompile(exec, m_evalCodeBlock.get(), m_jitCodeForCall); - if (dfgCompiled) - ASSERT(!m_evalCodeBlock->alternative() || !m_evalCodeBlock->alternative()->hasIncomingCalls()); - else { - if (m_evalCodeBlock->alternative()) { - // There is already an alternative piece of code compiled with a different - // JIT, so we can silently fail. - m_evalCodeBlock = static_pointer_cast<EvalCodeBlock>(m_evalCodeBlock->releaseAlternative()); - return 0; - } - m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_evalCodeBlock.get()); - } -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - m_evalCodeBlock->handleBytecodeDiscardingOpportunity(); -#endif - m_evalCodeBlock->setJITCode(m_jitCodeForCall, MacroAssemblerCodePtr()); - } + if (!jitCompileIfAppropriate(*globalData, m_evalCodeBlock, m_jitCodeForCall, jitType)) + return 0; #endif #if ENABLE(JIT) @@ -354,26 +338,8 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc } #if ENABLE(JIT) - if (exec->globalData().canUseJIT()) { - bool dfgCompiled = false; - if (jitType == JITCode::DFGJIT) - dfgCompiled = DFG::tryCompile(exec, m_programCodeBlock.get(), m_jitCodeForCall); - if (dfgCompiled) { - if (m_programCodeBlock->alternative()) - m_programCodeBlock->alternative()->unlinkIncomingCalls(); - } else { - if (m_programCodeBlock->alternative()) { - m_programCodeBlock = static_pointer_cast<ProgramCodeBlock>(m_programCodeBlock->releaseAlternative()); - return 0; - } - m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get()); - } -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - m_programCodeBlock->handleBytecodeDiscardingOpportunity(); -#endif - m_programCodeBlock->setJITCode(m_jitCodeForCall, MacroAssemblerCodePtr()); - } + if (!jitCompileIfAppropriate(*globalData, m_programCodeBlock, m_jitCodeForCall, jitType)) + return 0; #endif #if ENABLE(JIT) @@ -540,29 +506,8 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); #if ENABLE(JIT) - JSGlobalData* globalData = scopeChainNode->globalData; - if (globalData->canUseJIT()) { - bool dfgCompiled = false; - if (jitType == JITCode::DFGJIT) - dfgCompiled = DFG::tryCompileFunction(exec, m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck); - if (dfgCompiled) { - if (m_codeBlockForCall->alternative()) - m_codeBlockForCall->alternative()->unlinkIncomingCalls(); - } else { - if (m_codeBlockForCall->alternative()) { - m_codeBlockForCall = static_pointer_cast<FunctionCodeBlock>(m_codeBlockForCall->releaseAlternative()); - m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); - return 0; - } - m_jitCodeForCall = JIT::compile(globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck); - } -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - m_codeBlockForCall->handleBytecodeDiscardingOpportunity(); -#endif - - m_codeBlockForCall->setJITCode(m_jitCodeForCall, m_jitCodeForCallWithArityCheck); - } + if (!jitCompileFunctionIfAppropriate(exec->globalData(), m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, jitType)) + return 0; #endif #if ENABLE(JIT) @@ -603,29 +548,8 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); #if ENABLE(JIT) - JSGlobalData* globalData = scopeChainNode->globalData; - if (globalData->canUseJIT()) { - bool dfgCompiled = false; - if (jitType == JITCode::DFGJIT) - dfgCompiled = DFG::tryCompileFunction(exec, m_codeBlockForConstruct.get(), m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck); - if (dfgCompiled) { - if (m_codeBlockForConstruct->alternative()) - m_codeBlockForConstruct->alternative()->unlinkIncomingCalls(); - } else { - if (m_codeBlockForConstruct->alternative()) { - m_codeBlockForConstruct = static_pointer_cast<FunctionCodeBlock>(m_codeBlockForConstruct->releaseAlternative()); - m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); - return 0; - } - m_jitCodeForConstruct = JIT::compile(globalData, m_codeBlockForConstruct.get(), &m_jitCodeForConstructWithArityCheck); - } -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - m_codeBlockForConstruct->handleBytecodeDiscardingOpportunity(); -#endif - - m_codeBlockForConstruct->setJITCode(m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck); - } + if (!jitCompileFunctionIfAppropriate(exec->globalData(), m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, jitType)) + return 0; #endif #if ENABLE(JIT) @@ -738,7 +662,7 @@ FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functio FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); ASSERT(body); - return FunctionExecutable::create(exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); + return FunctionExecutable::create(exec->globalData(), functionName, functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); } UString FunctionExecutable::paramString() const diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index cc44d61a7..6800b5a82 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -87,7 +87,7 @@ namespace JSC { static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); } - static const ClassInfo s_info; + static JS_EXPORTDATA const ClassInfo s_info; protected: static const unsigned StructureFlags = 0; @@ -456,17 +456,17 @@ namespace JSC { public: typedef ScriptExecutable Base; - static FunctionExecutable* create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) + static FunctionExecutable* create(ExecState* exec, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) { - FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext); + FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext); executable->finishCreation(exec->globalData(), name, firstLine, lastLine); exec->globalData().heap.addFinalizer(executable, &finalize); return executable; } - static FunctionExecutable* create(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) + static FunctionExecutable* create(JSGlobalData& globalData, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) { - FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext); + FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext); executable->finishCreation(globalData, name, firstLine, lastLine); globalData.heap.addFinalizer(executable, &finalize); return executable; @@ -608,6 +608,7 @@ namespace JSC { } const Identifier& name() { return m_name; } + const Identifier& inferredName() { return m_inferredName; } JSString* nameValue() const { return m_nameValue.get(); } size_t parameterCount() const { return m_parameters->size(); } // Excluding 'this'! unsigned capturedVariableCount() const { return m_numCapturedVariables; } @@ -639,8 +640,8 @@ namespace JSC { } private: - FunctionExecutable(JSGlobalData&, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool); - FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool); + FunctionExecutable(JSGlobalData&, const Identifier& name, const Identifier& inferredName, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool); + FunctionExecutable(ExecState*, const Identifier& name, const Identifier& inferredName, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool); JSObject* compileForCallInternal(ExecState*, ScopeChainNode*, JITCode::JITType); JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*, JITCode::JITType); @@ -661,6 +662,7 @@ namespace JSC { OwnPtr<FunctionCodeBlock> m_codeBlockForCall; OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct; Identifier m_name; + Identifier m_inferredName; WriteBarrier<JSString> m_nameValue; SharedSymbolTable* m_symbolTable; }; diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp index e08e58c83..956b2161d 100644 --- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp +++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -96,17 +96,17 @@ JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState* exec, JSGlobalObj if (args.isEmpty()) program = "(function() { \n})"; else if (args.size() == 1) - program = makeUString("(function() { ", args.at(0).toString(exec), "\n})"); + program = makeUString("(function() { ", args.at(0).toString(exec)->value(exec), "\n})"); else { UStringBuilder builder; builder.append("(function("); - builder.append(args.at(0).toString(exec)); + builder.append(args.at(0).toString(exec)->value(exec)); for (size_t i = 1; i < args.size() - 1; i++) { builder.append(","); - builder.append(args.at(i).toString(exec)); + builder.append(args.at(i).toString(exec)->value(exec)); } builder.append(") { "); - builder.append(args.at(args.size() - 1).toString(exec)); + builder.append(args.at(args.size() - 1).toString(exec)->value(exec)); builder.append("\n})"); program = builder.toUString(); } diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.h b/Source/JavaScriptCore/runtime/FunctionConstructor.h index 7141916cf..31986b70a 100644 --- a/Source/JavaScriptCore/runtime/FunctionConstructor.h +++ b/Source/JavaScriptCore/runtime/FunctionConstructor.h @@ -59,7 +59,7 @@ namespace JSC { JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const UString& sourceURL, const WTF::TextPosition&); JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&); - JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState*, JSGlobalObject*, const ArgList&, const Identifier&, const UString&, const WTF::TextPosition&); + JS_EXPORT_PRIVATE JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState*, JSGlobalObject*, const ArgList&, const Identifier&, const UString&, const WTF::TextPosition&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp index 049b7b914..266ddc241 100644 --- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -207,7 +207,7 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec) length = targetLength - numBoundArgs; } - Identifier name(exec, target.get(exec, exec->propertyNames().name).toString(exec)); + Identifier name(exec, target.get(exec, exec->propertyNames().name).toString(exec)->value(exec)); return JSValue::encode(JSBoundFunction::create(exec, globalObject, targetObject, exec->argument(0), boundArgs, length, name)); } diff --git a/Source/JavaScriptCore/runtime/GetterSetter.h b/Source/JavaScriptCore/runtime/GetterSetter.h index 293bf6434..b8caf0198 100644 --- a/Source/JavaScriptCore/runtime/GetterSetter.h +++ b/Source/JavaScriptCore/runtime/GetterSetter.h @@ -56,9 +56,9 @@ namespace JSC { static void visitChildren(JSCell*, SlotVisitor&); JSObject* getter() const { return m_getter.get(); } - void setGetter(JSGlobalData& globalData, JSObject* getter) { m_getter.set(globalData, this, getter); } + void setGetter(JSGlobalData& globalData, JSObject* getter) { m_getter.setMayBeNull(globalData, this, getter); } JSObject* setter() const { return m_setter.get(); } - void setSetter(JSGlobalData& globalData, JSObject* setter) { m_setter.set(globalData, this, setter); } + void setSetter(JSGlobalData& globalData, JSObject* setter) { m_setter.setMayBeNull(globalData, this, setter); } static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(globalData, globalObject, prototype, TypeInfo(GetterSetterType, OverridesVisitChildren), &s_info); diff --git a/Source/JavaScriptCore/runtime/Identifier.h b/Source/JavaScriptCore/runtime/Identifier.h index 2cc88b256..947c95b33 100644 --- a/Source/JavaScriptCore/runtime/Identifier.h +++ b/Source/JavaScriptCore/runtime/Identifier.h @@ -56,14 +56,14 @@ namespace JSC { static Identifier createLCharFromUChar(JSGlobalData* globalData, const UChar* s, int length) { return Identifier(globalData, add8(globalData, s, length)); } - static Identifier from(ExecState* exec, unsigned y); - static Identifier from(ExecState* exec, int y); + JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, unsigned y); + JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, int y); static Identifier from(ExecState* exec, double y); static Identifier from(JSGlobalData*, unsigned y); static Identifier from(JSGlobalData*, int y); static Identifier from(JSGlobalData*, double y); - static uint32_t toUInt32(const UString&, bool& ok); + JS_EXPORT_PRIVATE static uint32_t toUInt32(const UString&, bool& ok); uint32_t toUInt32(bool& ok) const { return toUInt32(m_string, ok); } unsigned toArrayIndex(bool& ok) const; @@ -84,7 +84,7 @@ namespace JSC { static bool equal(const StringImpl*, const UChar*, unsigned length); static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); } - static PassRefPtr<StringImpl> add(ExecState*, const char*); // Only to be used with string literals. + JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(ExecState*, const char*); // Only to be used with string literals. static PassRefPtr<StringImpl> add(JSGlobalData*, const char*); // Only to be used with string literals. private: @@ -119,11 +119,11 @@ namespace JSC { return addSlowCase(globalData, r); } - static PassRefPtr<StringImpl> addSlowCase(ExecState*, StringImpl* r); - static PassRefPtr<StringImpl> addSlowCase(JSGlobalData*, StringImpl* r); + JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(ExecState*, StringImpl* r); + JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(JSGlobalData*, StringImpl* r); - static void checkCurrentIdentifierTable(ExecState*); - static void checkCurrentIdentifierTable(JSGlobalData*); + JS_EXPORT_PRIVATE static void checkCurrentIdentifierTable(ExecState*); + JS_EXPORT_PRIVATE static void checkCurrentIdentifierTable(JSGlobalData*); }; template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar) diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.h b/Source/JavaScriptCore/runtime/InitializeThreading.h index 1a93ccb9b..91301a0d8 100644 --- a/Source/JavaScriptCore/runtime/InitializeThreading.h +++ b/Source/JavaScriptCore/runtime/InitializeThreading.h @@ -33,7 +33,7 @@ namespace JSC { // This function must be called from the main thread. It is safe to call it repeatedly. // Darwin is an exception to this rule: it is OK to call this function from any thread, even reentrantly. - void initializeThreading(); + JS_EXPORT_PRIVATE void initializeThreading(); } diff --git a/Source/JavaScriptCore/runtime/InternalFunction.h b/Source/JavaScriptCore/runtime/InternalFunction.h index a038b7ae1..532bd0c8d 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.h +++ b/Source/JavaScriptCore/runtime/InternalFunction.h @@ -37,7 +37,7 @@ namespace JSC { static JS_EXPORTDATA const ClassInfo s_info; - const UString& name(ExecState*); + JS_EXPORT_PRIVATE const UString& name(ExecState*); const UString displayName(ExecState*); const UString calculatedDisplayName(ExecState*); @@ -49,9 +49,9 @@ namespace JSC { protected: static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags; - InternalFunction(JSGlobalObject*, Structure*); + JS_EXPORT_PRIVATE InternalFunction(JSGlobalObject*, Structure*); - void finishCreation(JSGlobalData&, const Identifier& name); + JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&, const Identifier& name); static CallType getCallData(JSCell*, CallData&); }; diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp index 83d1ee493..3e05738eb 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.cpp +++ b/Source/JavaScriptCore/runtime/JSActivation.cpp @@ -45,7 +45,7 @@ JSActivation::JSActivation(CallFrame* callFrame, FunctionExecutable* functionExe : Base(callFrame->globalData(), callFrame->globalData().activationStructure.get(), functionExecutable->symbolTable(), callFrame->registers()) , m_numCapturedArgs(max(callFrame->argumentCount(), functionExecutable->parameterCount())) , m_numCapturedVars(functionExecutable->capturedVariableCount()) - , m_requiresDynamicChecks(functionExecutable->usesEval()) + , m_requiresDynamicChecks(functionExecutable->usesEval() && !functionExecutable->isStrictMode()) , m_argumentsRegister(functionExecutable->generatedBytecode().argumentsRegister()) { } @@ -184,11 +184,11 @@ void JSActivation::put(JSCell* cell, ExecState* exec, const Identifier& property // properties are non-standard extensions that other implementations do not // expose in the activation object. ASSERT(!thisObject->hasGetterSetterProperties()); - thisObject->putDirect(exec->globalData(), propertyName, value, 0, true, slot); + thisObject->putOwnDataProperty(exec->globalData(), propertyName, value, slot); } // FIXME: Make this function honor ReadOnly (const) and DontEnum -void JSActivation::putWithAttributes(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) +void JSActivation::putDirectVirtual(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) { JSActivation* thisObject = jsCast<JSActivation*>(object); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); @@ -200,7 +200,7 @@ void JSActivation::putWithAttributes(JSObject* object, ExecState* exec, const Id // properties are non-standard extensions that other implementations do not // expose in the activation object. ASSERT(!thisObject->hasGetterSetterProperties()); - JSObject::putWithAttributes(thisObject, exec, propertyName, value, attributes); + JSObject::putDirectVirtual(thisObject, exec, propertyName, value, attributes); } bool JSActivation::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName) diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h index 2ce053e05..c18492344 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.h +++ b/Source/JavaScriptCore/runtime/JSActivation.h @@ -64,7 +64,7 @@ namespace JSC { static void put(JSCell*, ExecState*, const Identifier&, JSValue, PutPropertySlot&); - static void putWithAttributes(JSObject*, ExecState*, const Identifier&, JSValue, unsigned attributes); + static void putDirectVirtual(JSObject*, ExecState*, const Identifier&, JSValue, unsigned attributes); static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName); static JSObject* toThisObject(JSCell*, ExecState*); diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index b3210083d..c84fb5b10 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -24,6 +24,8 @@ #include "JSArray.h" #include "ArrayPrototype.h" +#include "BumpSpace.h" +#include "BumpSpaceInlineMethods.h" #include "CachedCall.h" #include "Error.h" #include "Executable.h" @@ -130,7 +132,10 @@ inline void JSArray::checkConsistency(ConsistencyCheckType) JSArray::JSArray(JSGlobalData& globalData, Structure* structure) : JSNonFinalObject(globalData, structure) + , m_indexBias(0) , m_storage(0) + , m_sparseValueMap(0) + , m_subclassData(0) { } @@ -142,13 +147,14 @@ void JSArray::finishCreation(JSGlobalData& globalData, unsigned initialLength) unsigned initialVectorLength = BASE_VECTOR_LEN; unsigned initialStorageSize = storageSize(initialVectorLength); - m_storage = static_cast<ArrayStorage*>(fastMalloc(initialStorageSize)); + void* newStorage = 0; + if (!globalData.heap.tryAllocateStorage(initialStorageSize, &newStorage)) + CRASH(); + + m_storage = static_cast<ArrayStorage*>(newStorage); m_storage->m_allocBase = m_storage; m_storage->m_length = initialLength; - m_indexBias = 0; m_vectorLength = initialVectorLength; - m_storage->m_sparseValueMap = 0; - m_storage->subclassData = 0; m_storage->m_numValuesInVector = 0; #if CHECK_ARRAY_CONSISTENCY m_storage->m_inCompactInitialization = false; @@ -159,8 +165,6 @@ void JSArray::finishCreation(JSGlobalData& globalData, unsigned initialLength) vector[i].clear(); checkConsistency(); - - Heap::heap(this)->reportExtraMemoryCost(initialStorageSize); } JSArray* JSArray::tryFinishCreationUninitialized(JSGlobalData& globalData, unsigned initialLength) @@ -175,14 +179,16 @@ JSArray* JSArray::tryFinishCreationUninitialized(JSGlobalData& globalData, unsig unsigned initialVectorLength = max(initialLength, BASE_VECTOR_LEN); unsigned initialStorageSize = storageSize(initialVectorLength); - m_storage = static_cast<ArrayStorage*>(fastMalloc(initialStorageSize)); + void* newStorage = 0; + if (!globalData.heap.tryAllocateStorage(initialStorageSize, &newStorage)) + CRASH(); + + m_storage = static_cast<ArrayStorage*>(newStorage); m_storage->m_allocBase = m_storage; m_storage->m_length = 0; - m_indexBias = 0; m_vectorLength = initialVectorLength; - m_storage->m_sparseValueMap = 0; - m_storage->subclassData = 0; m_storage->m_numValuesInVector = initialLength; + #if CHECK_ARRAY_CONSISTENCY m_storage->m_inCompactInitialization = true; #endif @@ -191,26 +197,15 @@ JSArray* JSArray::tryFinishCreationUninitialized(JSGlobalData& globalData, unsig for (size_t i = initialLength; i < initialVectorLength; ++i) vector[i].clear(); - Heap::heap(this)->reportExtraMemoryCost(initialStorageSize); return this; } -JSArray::~JSArray() -{ - ASSERT(jsCast<JSArray*>(this)); - - // If we are unable to allocate memory for m_storage then this may be null. - if (!m_storage) - return; - - checkConsistency(DestructorConsistencyCheck); - delete m_storage->m_sparseValueMap; - fastFree(m_storage->m_allocBase); -} - -void JSArray::destroy(JSCell* cell) +// This function can be called multiple times on the same object. +void JSArray::finalize(JSCell* cell) { - jsCast<JSArray*>(cell)->JSArray::~JSArray(); + JSArray* thisObject = jsCast<JSArray*>(cell); + thisObject->checkConsistency(DestructorConsistencyCheck); + thisObject->deallocateSparseMap(); } inline std::pair<SparseArrayValueMap::iterator, bool> SparseArrayValueMap::add(JSArray* array, unsigned i) @@ -229,7 +224,7 @@ inline void SparseArrayValueMap::put(ExecState* exec, JSArray* array, unsigned i { SparseArrayEntry& entry = add(array, i).first->second; - if (!(entry.attributes & (Getter | Setter))) { + if (!(entry.attributes & Accessor)) { if (entry.attributes & ReadOnly) { // FIXME: should throw if being called from strict mode. // throwTypeError(exec, StrictModeReadonlyPropertyWriteError); @@ -310,13 +305,27 @@ inline void SparseArrayValueMap::visitChildren(SlotVisitor& visitor) visitor.append(&it->second); } -void JSArray::enterSparseMode(JSGlobalData& globalData) +void JSArray::allocateSparseMap(JSGlobalData& globalData) +{ + m_sparseValueMap = new SparseArrayValueMap; + globalData.heap.addFinalizer(this, finalize); +} + +void JSArray::deallocateSparseMap() +{ + delete m_sparseValueMap; + m_sparseValueMap = 0; +} + +void JSArray::enterDictionaryMode(JSGlobalData& globalData) { ArrayStorage* storage = m_storage; - SparseArrayValueMap* map = storage->m_sparseValueMap; + SparseArrayValueMap* map = m_sparseValueMap; - if (!map) - map = storage->m_sparseValueMap = new SparseArrayValueMap; + if (!map) { + allocateSparseMap(globalData); + map = m_sparseValueMap; + } if (map->sparseMode()) return; @@ -332,10 +341,13 @@ void JSArray::enterSparseMode(JSGlobalData& globalData) map->add(this, i).first->second.set(globalData, this, value); } - ArrayStorage* newStorage = static_cast<ArrayStorage*>(fastMalloc(storageSize(0))); + void* newRawStorage = 0; + if (!globalData.heap.tryAllocateStorage(storageSize(0), &newRawStorage)) + CRASH(); + + ArrayStorage* newStorage = static_cast<ArrayStorage*>(newRawStorage); memcpy(newStorage, m_storage, storageSize(0)); newStorage->m_allocBase = newStorage; - fastFree(m_storage); m_storage = newStorage; m_indexBias = 0; m_vectorLength = 0; @@ -348,25 +360,21 @@ void JSArray::putDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, Prope entryInMap->set(exec->globalData(), this, descriptor.value()); else if (oldDescriptor.isAccessorDescriptor()) entryInMap->set(exec->globalData(), this, jsUndefined()); - entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~(Getter | Setter); + entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~Accessor; return; } if (descriptor.isAccessorDescriptor()) { JSObject* getter = 0; - if (descriptor.getter() && descriptor.getter().isObject()) - getter = asObject(descriptor.getter()); - if (!getter && oldDescriptor.isAccessorDescriptor()) { - if (oldDescriptor.getter() && oldDescriptor.getter().isObject()) - getter = asObject(oldDescriptor.getter()); - } + if (descriptor.getterPresent()) + getter = descriptor.getterObject(); + else if (oldDescriptor.isAccessorDescriptor()) + getter = oldDescriptor.getterObject(); JSObject* setter = 0; - if (descriptor.setter() && descriptor.setter().isObject()) - setter = asObject(descriptor.setter()); - if (!setter && oldDescriptor.isAccessorDescriptor()) { - if (oldDescriptor.setter() && oldDescriptor.setter().isObject()) - setter = asObject(oldDescriptor.setter()); - } + if (descriptor.setterPresent()) + setter = descriptor.setterObject(); + else if (oldDescriptor.isAccessorDescriptor()) + setter = oldDescriptor.setterObject(); GetterSetter* accessor = GetterSetter::create(exec); if (getter) @@ -406,10 +414,10 @@ bool JSArray::defineOwnNumericProperty(ExecState* exec, unsigned index, Property return true; } - enterSparseMode(exec->globalData()); + enterDictionaryMode(exec->globalData()); } - SparseArrayValueMap* map = m_storage->m_sparseValueMap; + SparseArrayValueMap* map = m_sparseValueMap; ASSERT(map); // 1. Let current be the result of calling the [[GetOwnProperty]] internal method of O with property name P. @@ -491,6 +499,7 @@ bool JSArray::defineOwnNumericProperty(ExecState* exec, unsigned index, Property } // 10.b. else, the [[Configurable]] field of current is true, so any change is acceptable. } else { + ASSERT(current.isAccessorDescriptor() && current.getterPresent() && current.setterPresent()); // 11. Else, IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true so, if the [[Configurable]] field of current is false, then if (!current.configurable()) { // 11.i. Reject, if the [[Set]] field of Desc is present and SameValue(Desc.[[Set]], current.[[Set]]) is false. @@ -515,9 +524,9 @@ void JSArray::setLengthWritable(ExecState* exec, bool writable) if (!isLengthWritable() || writable) return; - enterSparseMode(exec->globalData()); + enterDictionaryMode(exec->globalData()); - SparseArrayValueMap* map = m_storage->m_sparseValueMap; + SparseArrayValueMap* map = m_sparseValueMap; ASSERT(map); map->setLengthIsReadOnly(); } @@ -531,10 +540,10 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, const Identif if (propertyName == exec->propertyNames().length) { // All paths through length definition call the default [[DefineOwnProperty]], hence: // from ES5.1 8.12.9 7.a. - if (descriptor.configurable()) + if (descriptor.configurablePresent() && descriptor.configurable()) return reject(exec, throwException, "Attempting to change configurable attribute of unconfigurable property."); // from ES5.1 8.12.9 7.b. - if (descriptor.enumerable()) + if (descriptor.enumerablePresent() && descriptor.enumerable()) return reject(exec, throwException, "Attempting to change enumerable attribute of unconfigurable property."); // a. If the [[Value]] field of Desc is absent, then @@ -542,11 +551,12 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, const Identif if (descriptor.isAccessorDescriptor()) return reject(exec, throwException, "Attempting to change access mechanism for an unconfigurable property."); // from ES5.1 8.12.9 10.a. - if (!array->isLengthWritable() && descriptor.writable()) + if (!array->isLengthWritable() && descriptor.writablePresent() && descriptor.writable()) return reject(exec, throwException, "Attempting to change writable attribute of unconfigurable property."); // This descriptor is either just making length read-only, or changing nothing! if (!descriptor.value()) { - array->setLengthWritable(exec, descriptor.writable()); + if (descriptor.writablePresent()) + array->setLengthWritable(exec, descriptor.writable()); return true; } @@ -561,7 +571,8 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, const Identif // Based on SameValue check in 8.12.9, this is always okay. if (newLen == array->length()) { - array->setLengthWritable(exec, descriptor.writable()); + if (descriptor.writablePresent()) + array->setLengthWritable(exec, descriptor.writable()); return true; } @@ -588,13 +599,17 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, const Identif // 2. If newWritable is false, set newLenDesc.[[Writable] to false. // 3. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", newLenDesc, and false as arguments. // 4. Reject. - array->setLengthWritable(exec, descriptor.writable()); + if (descriptor.writablePresent()) + array->setLengthWritable(exec, descriptor.writable()); return false; } // m. If newWritable is false, then - // i. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", Property Descriptor{[[Writable]]: false}, and false as arguments. This call will always return true. - array->setLengthWritable(exec, descriptor.writable()); + // i. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", + // Property Descriptor{[[Writable]]: false}, and false as arguments. This call will always + // return true. + if (descriptor.writablePresent()) + array->setLengthWritable(exec, descriptor.writable()); // n. Return true. return true; } @@ -623,7 +638,7 @@ bool JSArray::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned { JSArray* thisObject = jsCast<JSArray*>(cell); ArrayStorage* storage = thisObject->m_storage; - + if (i >= storage->m_length) { if (i > MAX_ARRAY_INDEX) return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot); @@ -636,7 +651,7 @@ bool JSArray::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned slot.setValue(value); return true; } - } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + } else if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) { SparseArrayValueMap::iterator it = map->find(i); if (it != map->notFound()) { it->second.get(slot); @@ -684,7 +699,7 @@ bool JSArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const descriptor.setDescriptor(value.get(), 0); return true; } - } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + } else if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) { SparseArrayValueMap::iterator it = map->find(i); if (it != map->notFound()) { it->second.get(descriptor); @@ -765,7 +780,7 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne ASSERT(i <= MAX_ARRAY_INDEX); ArrayStorage* storage = m_storage; - SparseArrayValueMap* map = storage->m_sparseValueMap; + SparseArrayValueMap* map = m_sparseValueMap; // First, handle cases where we don't currently have a sparse map. if (LIKELY(!map)) { @@ -774,7 +789,7 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne storage->m_length = i + 1; // Check that it is sensible to still be using a vector, and then try to grow the vector. - if (LIKELY((isDenseEnoughForVector(i, storage->m_numValuesInVector)) && increaseVectorLength(i + 1))) { + if (LIKELY((isDenseEnoughForVector(i, storage->m_numValuesInVector)) && increaseVectorLength(globalData, i + 1))) { // success! - reread m_storage since it has likely been reallocated, and store to the vector. storage = m_storage; storage->m_vector[i].set(globalData, this, value); @@ -782,8 +797,8 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne return; } // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value. - map = new SparseArrayValueMap; - storage->m_sparseValueMap = map; + allocateSparseMap(exec->globalData()); + map = m_sparseValueMap; map->put(exec, this, i, value); return; } @@ -803,7 +818,7 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne // We are currently using a map - check whether we still want to be doing so. // We will continue to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails. unsigned numValuesInArray = storage->m_numValuesInVector + map->size(); - if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(length)) { + if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->globalData(), length)) { map->put(exec, this, i, value); return; } @@ -817,8 +832,7 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne SparseArrayValueMap::const_iterator end = map->end(); for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) vector[it->first].set(globalData, this, it->second.getNonSparseMode()); - delete map; - storage->m_sparseValueMap = 0; + deallocateSparseMap(); // Store the new property into the vector. WriteBarrier<Unknown>& valueSlot = vector[i]; @@ -857,7 +871,7 @@ bool JSArray::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) valueSlot.clear(); --storage->m_numValuesInVector; } - } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + } else if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) { SparseArrayValueMap::iterator it = map->find(i); if (it != map->notFound()) { if (it->second.attributes & DontDelete) @@ -892,7 +906,7 @@ void JSArray::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNam propertyNames.add(Identifier::from(exec, i)); } - if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) { Vector<unsigned> keys; keys.reserveCapacity(map->size()); @@ -940,7 +954,7 @@ ALWAYS_INLINE unsigned JSArray::getNewVectorLength(unsigned desiredLength) return min(increasedLength, MAX_STORAGE_VECTOR_LENGTH); } -bool JSArray::increaseVectorLength(unsigned newLength) +bool JSArray::increaseVectorLength(JSGlobalData& globalData, unsigned newLength) { // This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map // to the vector. Callers have to account for that, because they can do it more efficiently. @@ -952,15 +966,16 @@ bool JSArray::increaseVectorLength(unsigned newLength) unsigned vectorLength = m_vectorLength; ASSERT(newLength > vectorLength); unsigned newVectorLength = getNewVectorLength(newLength); - void* baseStorage = storage->m_allocBase; // Fast case - there is no precapacity. In these cases a realloc makes sense. if (LIKELY(!m_indexBias)) { - if (!tryFastRealloc(baseStorage, storageSize(newVectorLength)).getValue(baseStorage)) + void* newStorage = storage->m_allocBase; + if (!globalData.heap.tryReallocateStorage(&newStorage, storageSize(vectorLength), storageSize(newVectorLength))) return false; - storage = m_storage = reinterpret_cast_ptr<ArrayStorage*>(baseStorage); - m_storage->m_allocBase = baseStorage; + storage = m_storage = reinterpret_cast_ptr<ArrayStorage*>(static_cast<char*>(newStorage)); + m_storage->m_allocBase = newStorage; + ASSERT(m_storage->m_allocBase); WriteBarrier<Unknown>* vector = storage->m_vector; for (unsigned i = vectorLength; i < newVectorLength; ++i) @@ -968,7 +983,6 @@ bool JSArray::increaseVectorLength(unsigned newLength) m_vectorLength = newVectorLength; - Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); return true; } @@ -976,15 +990,11 @@ bool JSArray::increaseVectorLength(unsigned newLength) unsigned newIndexBias = min(m_indexBias >> 1, MAX_STORAGE_VECTOR_LENGTH - newVectorLength); // Calculate new stoarge capcity, allowing room for the pre-capacity. unsigned newStorageCapacity = newVectorLength + newIndexBias; - void* newAllocBase; - if (!tryFastMalloc(storageSize(newStorageCapacity)).getValue(newAllocBase)) + void* newAllocBase = 0; + if (!globalData.heap.tryAllocateStorage(storageSize(newStorageCapacity), &newAllocBase)) return false; // The sum of m_vectorLength and m_indexBias will never exceed MAX_STORAGE_VECTOR_LENGTH. ASSERT(m_vectorLength <= MAX_STORAGE_VECTOR_LENGTH && (MAX_STORAGE_VECTOR_LENGTH - m_vectorLength) >= m_indexBias); - unsigned currentCapacity = m_vectorLength + m_indexBias; - // Currently there is no way to report to the heap that the extra capacity is shrinking! - if (newStorageCapacity > currentCapacity) - Heap::heap(this)->reportExtraMemoryCost((newStorageCapacity - currentCapacity) * sizeof(WriteBarrier<Unknown>)); m_vectorLength = newVectorLength; m_indexBias = newIndexBias; @@ -996,14 +1006,13 @@ bool JSArray::increaseVectorLength(unsigned newLength) m_storage->m_vector[i].clear(); // Free the old allocation, update m_allocBase. - fastFree(m_storage->m_allocBase); m_storage->m_allocBase = newAllocBase; return true; } // This method makes room in the vector, but leaves the new space uncleared. -bool JSArray::unshiftCountSlowCase(unsigned count) +bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count) { // If not, we should have handled this on the fast path. ASSERT(count > m_indexBias); @@ -1034,19 +1043,16 @@ bool JSArray::unshiftCountSlowCase(unsigned count) // Step 2: // We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing on. - void* newAllocBase; + void* newAllocBase = 0; unsigned newStorageCapacity; // If the current storage array is sufficiently large (but not too large!) then just keep using it. if (currentCapacity > desiredCapacity && isDenseEnoughForVector(currentCapacity, requiredVectorLength)) { newAllocBase = storage->m_allocBase; newStorageCapacity = currentCapacity; } else { - if (!tryFastMalloc(storageSize(desiredCapacity)).getValue(newAllocBase)) + if (!globalData.heap.tryAllocateStorage(storageSize(desiredCapacity), &newAllocBase)) return false; newStorageCapacity = desiredCapacity; - // Currently there is no way to report to the heap that the extra capacity is shrinking! - if (desiredCapacity > currentCapacity) - Heap::heap(this)->reportExtraMemoryCost((desiredCapacity - currentCapacity) * sizeof(WriteBarrier<Unknown>)); } // Step 3: @@ -1079,7 +1085,6 @@ bool JSArray::unshiftCountSlowCase(unsigned count) // Are we copying into a new allocation? if (newAllocBase != m_storage->m_allocBase) { // Free the old allocation, update m_allocBase. - fastFree(m_storage->m_allocBase); m_storage->m_allocBase = newAllocBase; // We need to clear any entries in the vector beyond length. We only need to @@ -1101,9 +1106,9 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException unsigned length = storage->m_length; // If the length is read only then we enter sparse mode, so should enter the following 'if'. - ASSERT(isLengthWritable() || storage->m_sparseValueMap); + ASSERT(isLengthWritable() || m_sparseValueMap); - if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + if (SparseArrayValueMap* map = m_sparseValueMap) { // Fail if the length is not writable. if (map->lengthIsReadOnly()) return reject(exec, throwException, StrictModeReadonlyPropertyWriteError); @@ -1138,10 +1143,8 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException } else { for (unsigned i = 0; i < keys.size(); ++i) map->remove(keys[i]); - if (map->isEmpty()) { - delete map; - storage->m_sparseValueMap = 0; - } + if (map->isEmpty()) + deallocateSparseMap(); } } } @@ -1190,7 +1193,7 @@ JSValue JSArray::pop(ExecState* exec) result = jsUndefined(); } else { result = jsUndefined(); - if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + if (SparseArrayValueMap* map = m_sparseValueMap) { SparseArrayValueMap::iterator it = map->find(length); if (it != map->notFound()) { unsigned attributes = it->second.attributes; @@ -1206,10 +1209,8 @@ JSValue JSArray::pop(ExecState* exec) } map->remove(it); - if (map->isEmpty() && !map->sparseMode()) { - delete map; - storage->m_sparseValueMap = 0; - } + if (map->isEmpty() && !map->sparseMode()) + deallocateSparseMap(); } } } @@ -1331,7 +1332,7 @@ void JSArray::unshiftCount(ExecState* exec, unsigned count) memmove(newBaseStorage, storage, storageSize(0)); m_storage = reinterpret_cast_ptr<ArrayStorage*>(newBaseStorage); m_vectorLength += count; - } else if (!unshiftCountSlowCase(count)) { + } else if (!unshiftCountSlowCase(exec->globalData(), count)) { throwOutOfMemoryError(exec); return; } @@ -1349,13 +1350,21 @@ void JSArray::visitChildren(JSCell* cell, SlotVisitor& visitor) ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); JSNonFinalObject::visitChildren(thisObject, visitor); - - ArrayStorage* storage = thisObject->m_storage; - unsigned usedVectorLength = std::min(storage->m_length, thisObject->m_vectorLength); - visitor.appendValues(storage->m_vector, usedVectorLength); + if (thisObject->m_storage) { + ArrayStorage* storage = thisObject->m_storage; + void* baseStorage = storage->m_allocBase; + + visitor.copyAndAppend(reinterpret_cast<void**>(&baseStorage), storageSize(thisObject->m_vectorLength + thisObject->m_indexBias), storage->m_vector->slot(), thisObject->m_vectorLength); + + if (baseStorage != thisObject->m_storage->m_allocBase) { + thisObject->m_storage = reinterpret_cast<ArrayStorage*>(static_cast<char*>(baseStorage) + sizeof(JSValue) * thisObject->m_indexBias); + thisObject->m_storage->m_allocBase = baseStorage; + ASSERT(thisObject->m_storage->m_allocBase); + } + } - if (SparseArrayValueMap* map = storage->m_sparseValueMap) + if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) map->visitChildren(visitor); } @@ -1379,8 +1388,8 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal ArrayStorage* storage = m_storage; - unsigned lengthNotIncludingUndefined = compactForSorting(); - if (storage->m_sparseValueMap) { + unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData()); + if (m_sparseValueMap) { throwOutOfMemoryError(exec); return; } @@ -1412,10 +1421,8 @@ void JSArray::sort(ExecState* exec) { ASSERT(!inSparseMode()); - ArrayStorage* storage = m_storage; - - unsigned lengthNotIncludingUndefined = compactForSorting(); - if (storage->m_sparseValueMap) { + unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData()); + if (m_sparseValueMap) { throwOutOfMemoryError(exec); return; } @@ -1437,7 +1444,7 @@ void JSArray::sort(ExecState* exec) Heap::heap(this)->pushTempSortVector(&values); for (size_t i = 0; i < lengthNotIncludingUndefined; i++) { - JSValue value = storage->m_vector[i].get(); + JSValue value = m_storage->m_vector[i].get(); ASSERT(!value.isUndefined()); values[i].first = value; } @@ -1446,7 +1453,7 @@ void JSArray::sort(ExecState* exec) // a toString call raises an exception. for (size_t i = 0; i < lengthNotIncludingUndefined; i++) - values[i].second = values[i].first.toString(exec); + values[i].second = values[i].first.toString(exec)->value(exec); if (exec->hadException()) { Heap::heap(this)->popTempSortVector(&values); @@ -1467,13 +1474,13 @@ void JSArray::sort(ExecState* exec) // If the toString function changed the length of the array or vector storage, // increase the length to handle the orignal number of actual values. if (m_vectorLength < lengthNotIncludingUndefined) - increaseVectorLength(lengthNotIncludingUndefined); - if (storage->m_length < lengthNotIncludingUndefined) - storage->m_length = lengthNotIncludingUndefined; + increaseVectorLength(exec->globalData(), lengthNotIncludingUndefined); + if (m_storage->m_length < lengthNotIncludingUndefined) + m_storage->m_length = lengthNotIncludingUndefined; JSGlobalData& globalData = exec->globalData(); for (size_t i = 0; i < lengthNotIncludingUndefined; i++) - storage->m_vector[i].set(globalData, this, values[i].first); + m_storage->m_vector[i].set(globalData, this, values[i].first); Heap::heap(this)->popTempSortVector(&values); @@ -1563,18 +1570,16 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, checkConsistency(); - ArrayStorage* storage = m_storage; - // FIXME: This ignores exceptions raised in the compare function or in toNumber. // The maximum tree depth is compiled in - but the caller is clearly up to no good // if a larger array is passed. - ASSERT(storage->m_length <= static_cast<unsigned>(std::numeric_limits<int>::max())); - if (storage->m_length > static_cast<unsigned>(std::numeric_limits<int>::max())) + ASSERT(m_storage->m_length <= static_cast<unsigned>(std::numeric_limits<int>::max())); + if (m_storage->m_length > static_cast<unsigned>(std::numeric_limits<int>::max())) return; - unsigned usedVectorLength = min(storage->m_length, m_vectorLength); - unsigned nodeCount = usedVectorLength + (storage->m_sparseValueMap ? storage->m_sparseValueMap->size() : 0); + unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength); + unsigned nodeCount = usedVectorLength + (m_sparseValueMap ? m_sparseValueMap->size() : 0); if (!nodeCount) return; @@ -1602,14 +1607,14 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree. for (; numDefined < usedVectorLength; ++numDefined) { - JSValue v = storage->m_vector[numDefined].get(); + JSValue v = m_storage->m_vector[numDefined].get(); if (!v || v.isUndefined()) break; tree.abstractor().m_nodes[numDefined].value = v; tree.insert(numDefined); } for (unsigned i = numDefined; i < usedVectorLength; ++i) { - JSValue v = storage->m_vector[i].get(); + JSValue v = m_storage->m_vector[i].get(); if (v) { if (v.isUndefined()) ++numUndefined; @@ -1623,17 +1628,15 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, unsigned newUsedVectorLength = numDefined + numUndefined; - if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + if (SparseArrayValueMap* map = m_sparseValueMap) { newUsedVectorLength += map->size(); if (newUsedVectorLength > m_vectorLength) { // Check that it is possible to allocate an array large enough to hold all the entries. - if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) { + if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(exec->globalData(), newUsedVectorLength)) { throwOutOfMemoryError(exec); return; } } - - storage = m_storage; SparseArrayValueMap::const_iterator end = map->end(); for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) { @@ -1642,8 +1645,7 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, ++numDefined; } - delete map; - storage->m_sparseValueMap = 0; + deallocateSparseMap(); } ASSERT(tree.abstractor().m_nodes.size() >= numDefined); @@ -1656,19 +1658,19 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, iter.start_iter_least(tree); JSGlobalData& globalData = exec->globalData(); for (unsigned i = 0; i < numDefined; ++i) { - storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); + m_storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); ++iter; } // Put undefined values back in. for (unsigned i = numDefined; i < newUsedVectorLength; ++i) - storage->m_vector[i].setUndefined(); + m_storage->m_vector[i].setUndefined(); // Ensure that unused values in the vector are zeroed out. for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) - storage->m_vector[i].clear(); + m_storage->m_vector[i].clear(); - storage->m_numValuesInVector = newUsedVectorLength; + m_storage->m_numValuesInVector = newUsedVectorLength; checkConsistency(SortConsistencyCheck); } @@ -1709,7 +1711,7 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le callFrame->setArgument(i, get(exec, i)); } -unsigned JSArray::compactForSorting() +unsigned JSArray::compactForSorting(JSGlobalData& globalData) { ASSERT(!inSparseMode()); @@ -1740,12 +1742,12 @@ unsigned JSArray::compactForSorting() unsigned newUsedVectorLength = numDefined + numUndefined; - if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + if (SparseArrayValueMap* map = m_sparseValueMap) { newUsedVectorLength += map->size(); if (newUsedVectorLength > m_vectorLength) { // Check that it is possible to allocate an array large enough to hold all the entries - if not, // exception is thrown by caller. - if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) + if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(globalData, newUsedVectorLength)) return 0; storage = m_storage; @@ -1755,8 +1757,7 @@ unsigned JSArray::compactForSorting() for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) storage->m_vector[numDefined++].setWithoutWriteBarrier(it->second.getNonSparseMode()); - delete map; - storage->m_sparseValueMap = 0; + deallocateSparseMap(); } for (unsigned i = numDefined; i < newUsedVectorLength; ++i) @@ -1773,12 +1774,12 @@ unsigned JSArray::compactForSorting() void* JSArray::subclassData() const { - return m_storage->subclassData; + return m_subclassData; } void JSArray::setSubclassData(void* d) { - m_storage->subclassData = d; + m_subclassData = d; } #if CHECK_ARRAY_CONSISTENCY @@ -1791,7 +1792,7 @@ void JSArray::checkConsistency(ConsistencyCheckType type) ASSERT(storage); if (type == SortConsistencyCheck) - ASSERT(!storage->m_sparseValueMap); + ASSERT(!m_sparseValueMap); unsigned numValuesInVector = 0; for (unsigned i = 0; i < m_vectorLength; ++i) { @@ -1808,9 +1809,9 @@ void JSArray::checkConsistency(ConsistencyCheckType type) ASSERT(numValuesInVector == storage->m_numValuesInVector); ASSERT(numValuesInVector <= storage->m_length); - if (storage->m_sparseValueMap) { - SparseArrayValueMap::iterator end = storage->m_sparseValueMap->end(); - for (SparseArrayValueMap::iterator it = storage->m_sparseValueMap->begin(); it != end; ++it) { + if (m_sparseValueMap) { + SparseArrayValueMap::iterator end = m_sparseValueMap->end(); + for (SparseArrayValueMap::iterator it = m_sparseValueMap->begin(); it != end; ++it) { unsigned index = it->first; ASSERT(index < storage->m_length); ASSERT(index >= storage->m_vectorLength); diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index 871cfc882..a3354c602 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -114,8 +114,6 @@ namespace JSC { struct ArrayStorage { unsigned m_length; // The "length" property on the array unsigned m_numValuesInVector; - SparseArrayValueMap* m_sparseValueMap; - void* subclassData; // A JSArray subclass can use this to fill the vector lazily. void* m_allocBase; // Pointer to base address returned by malloc(). Keeping this pointer does eliminate false positives from the leak detector. #if CHECK_ARRAY_CONSISTENCY bool m_inCompactInitialization; @@ -127,16 +125,15 @@ namespace JSC { friend class Walker; protected: - explicit JSArray(JSGlobalData&, Structure*); + JS_EXPORT_PRIVATE explicit JSArray(JSGlobalData&, Structure*); - void finishCreation(JSGlobalData&, unsigned initialLength = 0); - JSArray* tryFinishCreationUninitialized(JSGlobalData&, unsigned initialLength); + JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&, unsigned initialLength = 0); + JS_EXPORT_PRIVATE JSArray* tryFinishCreationUninitialized(JSGlobalData&, unsigned initialLength); public: typedef JSNonFinalObject Base; - ~JSArray(); - static void destroy(JSCell*); + static void finalize(JSCell*); static JSArray* create(JSGlobalData& globalData, Structure* structure, unsigned initialLength = 0) { @@ -156,10 +153,10 @@ namespace JSC { return array->tryFinishCreationUninitialized(globalData, initialLength); } - static bool defineOwnProperty(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&, bool throwException); + JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&, bool throwException); static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&); - static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); + JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue); @@ -232,7 +229,7 @@ namespace JSC { bool inSparseMode() { - SparseArrayValueMap* map = m_storage->m_sparseValueMap; + SparseArrayValueMap* map = m_sparseValueMap; return map && map->sparseMode(); } @@ -254,7 +251,7 @@ namespace JSC { return OBJECT_OFFSETOF(JSArray, m_vectorLength); } - static void visitChildren(JSCell*, SlotVisitor&); + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; @@ -264,29 +261,31 @@ namespace JSC { static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - void* subclassData() const; - void setSubclassData(void*); + JS_EXPORT_PRIVATE void* subclassData() const; + JS_EXPORT_PRIVATE void setSubclassData(void*); private: bool isLengthWritable() { - SparseArrayValueMap* map = m_storage->m_sparseValueMap; + SparseArrayValueMap* map = m_sparseValueMap; return !map || !map->lengthIsReadOnly(); } void setLengthWritable(ExecState*, bool writable); void putDescriptor(ExecState*, SparseArrayEntry*, PropertyDescriptor&, PropertyDescriptor& old); bool defineOwnNumericProperty(ExecState*, unsigned, PropertyDescriptor&, bool throwException); - void enterSparseMode(JSGlobalData&); + void enterDictionaryMode(JSGlobalData&); + void allocateSparseMap(JSGlobalData&); + void deallocateSparseMap(); bool getOwnPropertySlotSlowCase(ExecState*, unsigned propertyName, PropertySlot&); void putByIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue); unsigned getNewVectorLength(unsigned desiredLength); - bool increaseVectorLength(unsigned newLength); - bool unshiftCountSlowCase(unsigned count); + bool increaseVectorLength(JSGlobalData&, unsigned newLength); + bool unshiftCountSlowCase(JSGlobalData&, unsigned count); - unsigned compactForSorting(); + unsigned compactForSorting(JSGlobalData&); enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck }; void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck); @@ -294,6 +293,10 @@ namespace JSC { unsigned m_vectorLength; // The valid length of m_vector unsigned m_indexBias; // The number of JSValue sized blocks before ArrayStorage. ArrayStorage *m_storage; + + // FIXME: Maybe SparseArrayValueMap should be put into its own JSCell? + SparseArrayValueMap* m_sparseValueMap; + void* m_subclassData; // A JSArray subclass can use this to fill the vector lazily. }; JSArray* asArray(JSValue); diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp index 549b6034f..88260ea27 100644 --- a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp @@ -111,8 +111,8 @@ void JSBoundFunction::finishCreation(ExecState* exec, NativeExecutable* executab Base::finishCreation(exec, executable, length, name); ASSERT(inherits(&s_info)); - initializeGetterSetterProperty(exec, exec->propertyNames().arguments, globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter); - initializeGetterSetterProperty(exec, exec->propertyNames().caller, globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter); + initializeGetterSetterProperty(exec, exec->propertyNames().arguments, globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); + initializeGetterSetterProperty(exec, exec->propertyNames().caller, globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); } void JSBoundFunction::visitChildren(JSCell* cell, SlotVisitor& visitor) diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.h b/Source/JavaScriptCore/runtime/JSBoundFunction.h index c60d7db01..e54d45883 100644 --- a/Source/JavaScriptCore/runtime/JSBoundFunction.h +++ b/Source/JavaScriptCore/runtime/JSBoundFunction.h @@ -51,7 +51,7 @@ public: return Structure::create(globalData, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), &s_info); } - static JS_EXPORTDATA const ClassInfo s_info; + static const ClassInfo s_info; protected: const static unsigned StructureFlags = OverridesHasInstance | OverridesVisitChildren | Base::StructureFlags; diff --git a/Source/JavaScriptCore/runtime/JSByteArray.h b/Source/JavaScriptCore/runtime/JSByteArray.h index 754774d3e..d1f4ad630 100644 --- a/Source/JavaScriptCore/runtime/JSByteArray.h +++ b/Source/JavaScriptCore/runtime/JSByteArray.h @@ -76,7 +76,7 @@ namespace JSC { } private: - JSByteArray(ExecState*, Structure*, ByteArray* storage); + JS_EXPORT_PRIVATE JSByteArray(ExecState*, Structure*, ByteArray* storage); public: static JSByteArray* create(ExecState* exec, Structure* structure, ByteArray* storage) @@ -86,15 +86,15 @@ namespace JSC { return array; } - static Structure* createStructure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const JSC::ClassInfo* = &s_info); + JS_EXPORT_PRIVATE static Structure* createStructure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const JSC::ClassInfo* = &s_info); - static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&); - static bool getOwnPropertySlotByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); - static void put(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&); - static void putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue); + JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&); + JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&); + JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); + JS_EXPORT_PRIVATE static void put(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&); + JS_EXPORT_PRIVATE static void putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue); - static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, EnumerationMode); + JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, EnumerationMode); static JS_EXPORTDATA const ClassInfo s_info; @@ -103,7 +103,7 @@ namespace JSC { WTF::ByteArray* storage() const { return m_storage.get(); } ~JSByteArray(); - static void destroy(JSCell*); + JS_EXPORT_PRIVATE static void destroy(JSCell*); static size_t offsetOfStorage() { return OBJECT_OFFSETOF(JSByteArray, m_storage); } diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp index 065fd13ea..9dcd6364b 100644 --- a/Source/JavaScriptCore/runtime/JSCell.cpp +++ b/Source/JavaScriptCore/runtime/JSCell.cpp @@ -145,13 +145,6 @@ double JSCell::toNumber(ExecState* exec) const return static_cast<const JSObject*>(this)->toNumber(exec); } -UString JSCell::toString(ExecState* exec) const -{ - if (isString()) - return static_cast<const JSString*>(this)->toString(exec); - return static_cast<const JSObject*>(this)->toString(exec); -} - JSObject* JSCell::toObject(ExecState* exec, JSGlobalObject* globalObject) const { if (isString()) @@ -203,7 +196,7 @@ bool JSCell::hasInstance(JSObject*, ExecState*, JSValue, JSValue) return false; } -void JSCell::putWithAttributes(JSObject*, ExecState*, const Identifier&, JSValue, unsigned) +void JSCell::putDirectVirtual(JSObject*, ExecState*, const Identifier&, JSValue, unsigned) { ASSERT_NOT_REACHED(); } diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index 47e336a86..a36bb7d58 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -51,6 +51,7 @@ namespace JSC { TypedArrayInt16, TypedArrayInt32, TypedArrayUint8, + TypedArrayUint8Clamped, TypedArrayUint16, TypedArrayUint32, TypedArrayFloat32, @@ -67,7 +68,7 @@ namespace JSC { protected: JSCell(JSGlobalData&, Structure*); - static void destroy(JSCell*); + JS_EXPORT_PRIVATE static void destroy(JSCell*); public: // Querying the type. @@ -82,21 +83,20 @@ namespace JSC { void clearStructure() { m_structure.clear(); } // Extracting the value. - bool getString(ExecState* exec, UString&) const; - UString getString(ExecState* exec) const; // null string if not a string - JSObject* getObject(); // NULL if not an object + JS_EXPORT_PRIVATE bool getString(ExecState* exec, UString&) const; + JS_EXPORT_PRIVATE UString getString(ExecState* exec) const; // null string if not a string + JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object const JSObject* getObject() const; // NULL if not an object - static CallType getCallData(JSCell*, CallData&); - static ConstructType getConstructData(JSCell*, ConstructData&); + JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&); + JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&); // Basic conversions. - JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; + JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; bool toBoolean(ExecState*) const; - double toNumber(ExecState*) const; - UString toString(ExecState*) const; - JSObject* toObject(ExecState*, JSGlobalObject*) const; + JS_EXPORT_PRIVATE double toNumber(ExecState*) const; + JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const; static void visitChildren(JSCell*, SlotVisitor&); @@ -159,7 +159,7 @@ namespace JSC { static NO_RETURN_DUE_TO_ASSERT void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); static UString className(const JSObject*); static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty); - static NO_RETURN_DUE_TO_ASSERT void putWithAttributes(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); + static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow); static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp index 65470a53f..15718a176 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSFunction.cpp @@ -136,7 +136,11 @@ const UString JSFunction::calculatedDisplayName(ExecState* exec) if (!explicitName.isEmpty()) return explicitName; - return name(exec); + const UString actualName = name(exec); + if (!actualName.isEmpty() || isHostFunction()) + return actualName; + + return jsExecutable()->inferredName().ustring(); } const SourceCode* JSFunction::sourceCode() const @@ -175,14 +179,14 @@ JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, const Ide { JSFunction* thisObj = asFunction(slotBase); ASSERT(!thisObj->isHostFunction()); - return exec->interpreter()->retrieveArguments(exec, thisObj); + return exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObj); } JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, const Identifier&) { JSFunction* thisObj = asFunction(slotBase); ASSERT(!thisObj->isHostFunction()); - return exec->interpreter()->retrieveCaller(exec, thisObj); + return exec->interpreter()->retrieveCallerFromVMCode(exec, thisObj); } JSValue JSFunction::lengthGetter(ExecState*, JSValue slotBase, const Identifier&) @@ -204,8 +208,7 @@ bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identif if (!location) { JSObject* prototype = constructEmptyObject(exec, thisObject->globalObject()->emptyObjectStructure()); prototype->putDirect(exec->globalData(), exec->propertyNames().constructor, thisObject, DontEnum); - PutPropertySlot slot; - thisObject->putDirect(exec->globalData(), exec->propertyNames().prototype, prototype, DontDelete | DontEnum, false, slot); + thisObject->putDirect(exec->globalData(), exec->propertyNames().prototype, prototype, DontDelete | DontEnum); location = thisObject->getDirectLocation(exec->globalData(), exec->propertyNames().prototype); } @@ -216,7 +219,7 @@ bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identif if (thisObject->jsExecutable()->isStrictMode()) { bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (!result) { - thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter); + thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); ASSERT(result); } @@ -235,7 +238,7 @@ bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identif if (thisObject->jsExecutable()->isStrictMode()) { bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (!result) { - thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter); + thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); ASSERT(result); } @@ -264,13 +267,13 @@ bool JSFunction::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, con if (thisObject->jsExecutable()->isStrictMode()) { bool result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); if (!result) { - thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter); + thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); ASSERT(result); } return result; } - descriptor.setDescriptor(exec->interpreter()->retrieveArguments(exec, thisObject), ReadOnly | DontEnum | DontDelete); + descriptor.setDescriptor(exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject), ReadOnly | DontEnum | DontDelete); return true; } @@ -283,13 +286,13 @@ bool JSFunction::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, con if (thisObject->jsExecutable()->isStrictMode()) { bool result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); if (!result) { - thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter); + thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); ASSERT(result); } return result; } - descriptor.setDescriptor(exec->interpreter()->retrieveCaller(exec, thisObject), ReadOnly | DontEnum | DontDelete); + descriptor.setDescriptor(exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject), ReadOnly | DontEnum | DontDelete); return true; } @@ -358,5 +361,15 @@ ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& construc constructData.js.scopeChain = thisObject->scope(); return ConstructTypeJS; } + + +UString getCalculatedDisplayName(CallFrame* callFrame, JSObject* object) +{ + if (JSFunction* function = jsDynamicCast<JSFunction*>(object)) + return function->calculatedDisplayName(callFrame); + if (InternalFunction* function = jsDynamicCast<InternalFunction*>(object)) + return function->calculatedDisplayName(callFrame); + return UString(); +} } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h index 5118f8b10..a12b079d7 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.h +++ b/Source/JavaScriptCore/runtime/JSFunction.h @@ -40,8 +40,10 @@ namespace JSC { class JITCompiler; } - EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*); + JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*); + JS_EXPORT_PRIVATE UString getCalculatedDisplayName(CallFrame*, JSObject*); + class JSFunction : public JSNonFinalObject { friend class JIT; friend class DFG::SpeculativeJIT; @@ -51,7 +53,7 @@ namespace JSC { public: typedef JSNonFinalObject Base; - static JSFunction* create(ExecState*, JSGlobalObject*, int length, const Identifier& name, NativeFunction nativeFunction, NativeFunction nativeConstructor = callHostFunctionAsConstructor); + JS_EXPORT_PRIVATE static JSFunction* create(ExecState*, JSGlobalObject*, int length, const Identifier& name, NativeFunction nativeFunction, NativeFunction nativeConstructor = callHostFunctionAsConstructor); static JSFunction* create(ExecState*, JSGlobalObject*, int length, const Identifier& name, NativeExecutable* nativeExecutable); static JSFunction* create(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChain) @@ -64,8 +66,8 @@ namespace JSC { static void destroy(JSCell*); - const UString& name(ExecState*); - const UString displayName(ExecState*); + JS_EXPORT_PRIVATE const UString& name(ExecState*); + JS_EXPORT_PRIVATE const UString displayName(ExecState*); const UString calculatedDisplayName(ExecState*); ScopeChainNode* scope() @@ -94,7 +96,7 @@ namespace JSC { inline bool isHostFunction() const; FunctionExecutable* jsExecutable() const; - const SourceCode* sourceCode() const; + JS_EXPORT_PRIVATE const SourceCode* sourceCode() const; static JS_EXPORTDATA const ClassInfo s_info; @@ -123,7 +125,7 @@ namespace JSC { protected: const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; - JSFunction(ExecState*, JSGlobalObject*, Structure*); + JS_EXPORT_PRIVATE JSFunction(ExecState*, JSGlobalObject*, Structure*); JSFunction(ExecState*, FunctionExecutable*, ScopeChainNode*); void finishCreation(ExecState*, NativeExecutable*, int length, const Identifier& name); @@ -140,7 +142,7 @@ namespace JSC { static void visitChildren(JSCell*, SlotVisitor&); private: - bool isHostFunctionNonInline() const; + JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const; static JSValue argumentsGetter(ExecState*, JSValue, const Identifier&); static JSValue callerGetter(ExecState*, JSValue, const Identifier&); diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp index dab3f24ba..bbe520a1e 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp @@ -101,7 +101,7 @@ extern const HashTable globalObjectTable; extern const HashTable mathTable; extern const HashTable numberConstructorTable; extern const HashTable numberPrototypeTable; -extern const HashTable objectConstructorTable; +JS_EXPORTDATA extern const HashTable objectConstructorTable; extern const HashTable objectPrototypeTable; extern const HashTable regExpTable; extern const HashTable regExpConstructorTable; @@ -162,8 +162,6 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread #endif { interpreter = new Interpreter; - if (globalDataType == Default) - m_stack = wtfThreadData().stack(); // Need to be careful to keep everything consistent here IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable); diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h index a6ad8a747..92817f2a2 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/JSGlobalData.h @@ -134,18 +134,18 @@ namespace JSC { enum GlobalDataType { Default, APIContextGroup, APIShared }; struct ClientData { - virtual ~ClientData() = 0; + JS_EXPORT_PRIVATE virtual ~ClientData() = 0; }; bool isSharedInstance() { return globalDataType == APIShared; } bool usingAPI() { return globalDataType != Default; } static bool sharedInstanceExists(); - static JSGlobalData& sharedInstance(); + JS_EXPORT_PRIVATE static JSGlobalData& sharedInstance(); - static PassRefPtr<JSGlobalData> create(ThreadStackType, HeapSize = SmallHeap); - static PassRefPtr<JSGlobalData> createLeaked(ThreadStackType, HeapSize = SmallHeap); + JS_EXPORT_PRIVATE static PassRefPtr<JSGlobalData> create(ThreadStackType, HeapSize = SmallHeap); + JS_EXPORT_PRIVATE static PassRefPtr<JSGlobalData> createLeaked(ThreadStackType, HeapSize = SmallHeap); static PassRefPtr<JSGlobalData> createContextGroup(ThreadStackType, HeapSize = SmallHeap); - ~JSGlobalData(); + JS_EXPORT_PRIVATE ~JSGlobalData(); void makeUsableFromMultipleThreads() { heap.machineThreads().makeUsableFromMultipleThreads(); } @@ -223,13 +223,6 @@ namespace JSC { bool canUseJIT() { return m_canUseJIT; } #endif - const StackBounds& stack() - { - return (globalDataType == Default) - ? m_stack - : wtfThreadData().stack(); - } - OwnPtr<ParserArena> parserArena; OwnPtr<Keywords> keywords; Interpreter* interpreter; @@ -308,21 +301,21 @@ namespace JSC { CachedTranscendentalFunction<sin> cachedSin; - void resetDateCache(); + JS_EXPORT_PRIVATE void resetDateCache(); - void startSampling(); - void stopSampling(); - void dumpSampleData(ExecState* exec); + JS_EXPORT_PRIVATE void startSampling(); + JS_EXPORT_PRIVATE void stopSampling(); + JS_EXPORT_PRIVATE void dumpSampleData(ExecState* exec); void recompileAllJSFunctions(); RegExpCache* regExpCache() { return m_regExpCache; } #if ENABLE(REGEXP_TRACING) void addRegExpToTrace(PassRefPtr<RegExp> regExp); #endif - void dumpRegExpTrace(); - void clearBuiltinStructures(); + JS_EXPORT_PRIVATE void dumpRegExpTrace(); + JS_EXPORT_PRIVATE void clearBuiltinStructures(); bool isCollectorBusy() { return heap.isBusy(); } - void releaseExecutableMemory(); + JS_EXPORT_PRIVATE void releaseExecutableMemory(); #if ENABLE(GC_VALIDATION) bool isInitializingObject() const; @@ -345,6 +338,7 @@ namespace JSC { registerTypedArrayFunction(int16, Int16); registerTypedArrayFunction(int32, Int32); registerTypedArrayFunction(uint8, Uint8); + registerTypedArrayFunction(uint8Clamped, Uint8Clamped); registerTypedArrayFunction(uint16, Uint16); registerTypedArrayFunction(uint32, Uint32); registerTypedArrayFunction(float32, Float32); @@ -358,7 +352,6 @@ namespace JSC { #if ENABLE(JIT) && ENABLE(INTERPRETER) bool m_canUseJIT; #endif - StackBounds m_stack; #if ENABLE(GC_VALIDATION) bool m_isInitializingObject; #endif @@ -366,6 +359,7 @@ namespace JSC { TypedArrayDescriptor m_int16ArrayDescriptor; TypedArrayDescriptor m_int32ArrayDescriptor; TypedArrayDescriptor m_uint8ArrayDescriptor; + TypedArrayDescriptor m_uint8ClampedArrayDescriptor; TypedArrayDescriptor m_uint16ArrayDescriptor; TypedArrayDescriptor m_uint32ArrayDescriptor; TypedArrayDescriptor m_float32ArrayDescriptor; diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index 5ad53c222..f28139d27 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -153,7 +153,7 @@ void JSGlobalObject::put(JSCell* cell, ExecState* exec, const Identifier& proper JSVariableObject::put(thisObject, exec, propertyName, value, slot); } -void JSGlobalObject::putWithAttributes(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) +void JSGlobalObject::putDirectVirtual(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) { JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); @@ -167,7 +167,7 @@ void JSGlobalObject::putWithAttributes(JSObject* object, ExecState* exec, const if (!valueBefore) { JSValue valueAfter = thisObject->getDirect(exec->globalData(), propertyName); if (valueAfter) - JSObject::putWithAttributes(thisObject, exec, propertyName, valueAfter, attributes); + JSObject::putDirectVirtual(thisObject, exec, propertyName, valueAfter, attributes); } } diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index 1caa8b187..70368307d 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -192,20 +192,20 @@ namespace JSC { } public: - ~JSGlobalObject(); - static void destroy(JSCell*); + JS_EXPORT_PRIVATE ~JSGlobalObject(); + JS_EXPORT_PRIVATE static void destroy(JSCell*); - static void visitChildren(JSCell*, SlotVisitor&); + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); - static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); + JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&); + JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); bool hasOwnPropertyForWrite(ExecState*, const Identifier&); - static void put(JSCell*, ExecState*, const Identifier&, JSValue, PutPropertySlot&); + JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, const Identifier&, JSValue, PutPropertySlot&); - static void putWithAttributes(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); + JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); - static void defineGetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes); - static void defineSetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes); + JS_EXPORT_PRIVATE static void defineGetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes); + JS_EXPORT_PRIVATE static void defineSetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes); // We use this in the code generator as we perform symbol table // lookups prior to initializing the properties @@ -283,7 +283,7 @@ namespace JSC { ScopeChainNode* globalScopeChain() { return m_globalScopeChain.get(); } - ExecState* globalExec(); + JS_EXPORT_PRIVATE ExecState* globalExec(); static bool shouldInterruptScript(const JSGlobalObject*) { return true; } @@ -332,17 +332,17 @@ namespace JSC { JSValue value; unsigned attributes; }; - void addStaticGlobals(GlobalPropertyInfo*, int count); + JS_EXPORT_PRIVATE void addStaticGlobals(GlobalPropertyInfo*, int count); private: // FIXME: Fold reset into init. - void init(JSObject* thisValue); + JS_EXPORT_PRIVATE void init(JSObject* thisValue); void reset(JSValue prototype); void createThrowTypeError(ExecState*); void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count); - static void clearRareData(JSCell*); + JS_EXPORT_PRIVATE static void clearRareData(JSCell*); }; JSGlobalObject* asGlobalObject(JSValue); @@ -488,7 +488,7 @@ namespace JSC { class DynamicGlobalObjectScope { WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope); public: - DynamicGlobalObjectScope(JSGlobalData&, JSGlobalObject*); + JS_EXPORT_PRIVATE DynamicGlobalObjectScope(JSGlobalData&, JSGlobalObject*); ~DynamicGlobalObjectScope() { diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index bf6b31ef1..b82ab62ab 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -51,8 +51,7 @@ namespace JSC { static JSValue encode(ExecState* exec, const char* doNotEscape) { - UString str = exec->argument(0).toString(exec); - CString cstr = str.utf8(true); + CString cstr = exec->argument(0).toString(exec)->value(exec).utf8(true); if (!cstr.data()) return throwError(exec, createURIError(exec, "String contained an illegal UTF-16 sequence.")); @@ -143,7 +142,7 @@ static JSValue decode(ExecState* exec, const CharType* characters, int length, c static JSValue decode(ExecState* exec, const char* doNotUnescape, bool strict) { JSStringBuilder builder; - UString str = exec->argument(0).toString(exec); + UString str = exec->argument(0).toString(exec)->value(exec); if (str.is8Bit()) return decode(exec, str.characters8(), str.length(), doNotUnescape, strict); @@ -513,7 +512,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec) if (!x.isString()) return JSValue::encode(x); - UString s = x.toString(exec); + UString s = x.toString(exec)->value(exec); if (s.is8Bit()) { LiteralParser<LChar> preparser(exec, s.characters8(), s.length(), NonStrictJSON); @@ -556,7 +555,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec) } // If ToString throws, we shouldn't call ToInt32. - UString s = value.toString(exec); + UString s = value.toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -565,7 +564,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec) EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec) { - return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec)))); + return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec)->value(exec)))); } EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec) @@ -623,7 +622,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec) "*+-./@_"; JSStringBuilder builder; - UString str = exec->argument(0).toString(exec); + UString str = exec->argument(0).toString(exec)->value(exec); if (str.is8Bit()) { const LChar* c = str.characters8(); for (unsigned k = 0; k < str.length(); k++, c++) { @@ -662,7 +661,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec) EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec) { UStringBuilder builder; - UString str = exec->argument(0).toString(exec); + UString str = exec->argument(0).toString(exec)->value(exec); int k = 0; int len = str.length(); diff --git a/Source/JavaScriptCore/runtime/JSGlobalThis.h b/Source/JavaScriptCore/runtime/JSGlobalThis.h index fa5de0491..fa5c2eb34 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalThis.h +++ b/Source/JavaScriptCore/runtime/JSGlobalThis.h @@ -63,7 +63,7 @@ protected: static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; - static void visitChildren(JSCell*, SlotVisitor&); + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); WriteBarrier<JSGlobalObject> m_unwrappedObject; }; diff --git a/Source/JavaScriptCore/runtime/JSLock.h b/Source/JavaScriptCore/runtime/JSLock.h index 7b07b4fb3..a0eb96975 100644 --- a/Source/JavaScriptCore/runtime/JSLock.h +++ b/Source/JavaScriptCore/runtime/JSLock.h @@ -56,7 +56,7 @@ namespace JSC { class JSLock { WTF_MAKE_NONCOPYABLE(JSLock); public: - JSLock(ExecState*); + JS_EXPORT_PRIVATE JSLock(ExecState*); JSLock(JSGlobalData*); JSLock(JSLockBehavior lockBehavior) @@ -80,22 +80,22 @@ namespace JSC { unlock(m_lockBehavior); } - static void lock(JSLockBehavior); - static void unlock(JSLockBehavior); + JS_EXPORT_PRIVATE static void lock(JSLockBehavior); + JS_EXPORT_PRIVATE static void unlock(JSLockBehavior); static void lock(ExecState*); static void unlock(ExecState*); - static intptr_t lockCount(); - static bool currentThreadIsHoldingLock(); + JS_EXPORT_PRIVATE static intptr_t lockCount(); + JS_EXPORT_PRIVATE static bool currentThreadIsHoldingLock(); JSLockBehavior m_lockBehavior; class DropAllLocks { WTF_MAKE_NONCOPYABLE(DropAllLocks); public: - DropAllLocks(ExecState* exec); - DropAllLocks(JSLockBehavior); - ~DropAllLocks(); + JS_EXPORT_PRIVATE DropAllLocks(ExecState* exec); + JS_EXPORT_PRIVATE DropAllLocks(JSLockBehavior); + JS_EXPORT_PRIVATE ~DropAllLocks(); private: intptr_t m_lockCount; diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp index 05c6c2953..83b118429 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.cpp +++ b/Source/JavaScriptCore/runtime/JSONObject.cpp @@ -142,7 +142,7 @@ static inline JSValue unwrapBoxedPrimitive(ExecState* exec, JSValue value) if (object->inherits(&NumberObject::s_info)) return jsNumber(object->toNumber(exec)); if (object->inherits(&StringObject::s_info)) - return jsString(exec, object->toString(exec)); + return object->toString(exec); if (object->inherits(&BooleanObject::s_info)) return object->toPrimitive(exec); return value; @@ -223,25 +223,12 @@ Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const if (exec->hadException()) break; - UString propertyName; - if (name.getString(exec, propertyName)) { - m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName)); - continue; - } - - if (name.isNumber()) { - m_arrayReplacerPropertyNames.add(Identifier::from(exec, name.asNumber())); - continue; - } - if (name.isObject()) { if (!asObject(name)->inherits(&NumberObject::s_info) && !asObject(name)->inherits(&StringObject::s_info)) continue; - propertyName = name.toString(exec); - if (exec->hadException()) - break; - m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName)); } + + m_arrayReplacerPropertyNames.add(Identifier(exec, name.toString(exec)->value(exec))); } return; } @@ -825,8 +812,7 @@ EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec) { if (!exec->argumentCount()) return throwVMError(exec, createError(exec, "JSON.parse requires at least one parameter")); - JSValue value = exec->argument(0); - UString source = value.toString(exec); + UString source = exec->argument(0).toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsNull()); diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index a813e8416..a443fda86 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -24,6 +24,7 @@ #include "config.h" #include "JSObject.h" +#include "BumpSpaceInlineMethods.h" #include "DatePrototype.h" #include "ErrorConstructor.h" #include "GetterSetter.h" @@ -83,11 +84,6 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class } } -void JSObject::finalize(JSCell* cell) -{ - delete [] jsCast<JSObject*>(cell)->m_propertyStorage.get(); -} - void JSObject::destroy(JSCell* cell) { jsCast<JSObject*>(cell)->JSObject::~JSObject(); @@ -106,7 +102,16 @@ void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor) PropertyStorage storage = thisObject->propertyStorage(); size_t storageSize = thisObject->structure()->propertyStorageSize(); - visitor.appendValues(storage, storageSize); + if (thisObject->isUsingInlineStorage()) + visitor.appendValues(storage, storageSize); + else { + // We have this extra temp here to slake GCC's thirst for the blood of those who dereference type-punned pointers. + void* temp = storage; + visitor.copyAndAppend(&temp, thisObject->structure()->propertyStorageCapacity() * sizeof(WriteBarrierBase<Unknown>), storage->slot(), storageSize); + storage = static_cast<PropertyStorage>(temp); + thisObject->m_propertyStorage.set(storage, StorageBarrier::Unchecked); + } + if (thisObject->m_inheritorID) visitor.append(&thisObject->m_inheritorID); @@ -162,7 +167,7 @@ void JSObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName for (JSObject* obj = thisObject; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) { prototype = obj->prototype(); if (prototype.isNull()) { - if (!thisObject->putDirectInternal(globalData, propertyName, value, 0, true, slot, getJSFunction(value)) && slot.isStrictMode()) + if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode()) throwTypeError(exec, StrictModeReadonlyPropertyWriteError); return; } @@ -205,7 +210,7 @@ void JSObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName break; } - if (!thisObject->putDirectInternal(globalData, propertyName, value, 0, true, slot, getJSFunction(value)) && slot.isStrictMode()) + if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode()) throwTypeError(exec, StrictModeReadonlyPropertyWriteError); return; } @@ -217,16 +222,28 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot); } -void JSObject::putWithAttributes(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) +void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) { + ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); PutPropertySlot slot; - object->putDirectInternal(exec->globalData(), propertyName, value, attributes, true, slot, getJSFunction(value)); + object->putDirectInternal<PutModeDefineOwnProperty>(exec->globalData(), propertyName, value, attributes, slot, getJSFunction(value)); } -void JSObject::putWithAttributes(JSGlobalData* globalData, const Identifier& propertyName, JSValue value, unsigned attributes) +void JSObject::putDirectAccessor(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) { + ASSERT(value.isGetterSetter() && (attributes & Accessor)); + ASSERT(propertyName != globalData.propertyNames->underscoreProto); + PutPropertySlot slot; - putDirectInternal(*globalData, propertyName, value, attributes, true, slot, getJSFunction(value)); + putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value)); + + // putDirect will change our Structure if we add a new property. For + // getters and setters, though, we also need to change our Structure + // if we override an existing non-getter or non-setter. + if (slot.type() != PutPropertySlot::NewProperty) + setStructure(globalData, Structure::attributeChangeTransition(globalData, structure(), propertyName, attributes)); + + structure()->setHasGetterSetterProperties(true); } bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const @@ -361,15 +378,13 @@ void JSObject::defineGetter(JSObject* thisObject, ExecState* exec, const Identif JSGlobalData& globalData = exec->globalData(); PutPropertySlot slot; GetterSetter* getterSetter = GetterSetter::create(exec); - thisObject->putDirectInternal(globalData, propertyName, getterSetter, attributes | Getter, true, slot, 0); + thisObject->putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, getterSetter, attributes | Accessor, slot, 0); // putDirect will change our Structure if we add a new property. For // getters and setters, though, we also need to change our Structure // if we override an existing non-getter or non-setter. - if (slot.type() != PutPropertySlot::NewProperty) { - if (!thisObject->structure()->isDictionary()) - thisObject->setStructure(exec->globalData(), Structure::getterSetterTransition(globalData, thisObject->structure())); - } + if (slot.type() != PutPropertySlot::NewProperty) + thisObject->setStructure(exec->globalData(), Structure::attributeChangeTransition(globalData, thisObject->structure(), propertyName, attributes | Accessor)); thisObject->structure()->setHasGetterSetterProperties(true); getterSetter->setGetter(globalData, getterFunction); @@ -379,20 +394,17 @@ void JSObject::initializeGetterSetterProperty(ExecState* exec, const Identifier& { // Set an inital property on an object; the property must not already exist & the attribute flags must be set correctly. ASSERT(structure()->get(exec->globalData(), propertyName) == WTF::notFound); - ASSERT(static_cast<bool>(getterSetter->getter()) == static_cast<bool>(attributes & Getter)); - ASSERT(static_cast<bool>(getterSetter->setter()) == static_cast<bool>(attributes & Setter)); + ASSERT(static_cast<bool>(attributes & Accessor)); JSGlobalData& globalData = exec->globalData(); PutPropertySlot slot; - putDirectInternal(globalData, propertyName, getterSetter, attributes | Getter, true, slot, 0); + putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, getterSetter, attributes, slot, 0); // putDirect will change our Structure if we add a new property. For // getters and setters, though, we also need to change our Structure // if we override an existing non-getter or non-setter. - if (slot.type() != PutPropertySlot::NewProperty) { - if (!structure()->isDictionary()) - setStructure(exec->globalData(), Structure::getterSetterTransition(globalData, structure())); - } + if (slot.type() != PutPropertySlot::NewProperty) + setStructure(exec->globalData(), Structure::attributeChangeTransition(globalData, structure(), propertyName, attributes)); structure()->setHasGetterSetterProperties(true); } @@ -413,15 +425,13 @@ void JSObject::defineSetter(JSObject* thisObject, ExecState* exec, const Identif PutPropertySlot slot; GetterSetter* getterSetter = GetterSetter::create(exec); - thisObject->putDirectInternal(exec->globalData(), propertyName, getterSetter, attributes | Setter, true, slot, 0); + thisObject->putDirectInternal<PutModeDefineOwnProperty>(exec->globalData(), propertyName, getterSetter, attributes | Accessor, slot, 0); // putDirect will change our Structure if we add a new property. For // getters and setters, though, we also need to change our Structure // if we override an existing non-getter or non-setter. - if (slot.type() != PutPropertySlot::NewProperty) { - if (!thisObject->structure()->isDictionary()) - thisObject->setStructure(exec->globalData(), Structure::getterSetterTransition(exec->globalData(), thisObject->structure())); - } + if (slot.type() != PutPropertySlot::NewProperty) + thisObject->setStructure(exec->globalData(), Structure::attributeChangeTransition(exec->globalData(), thisObject->structure(), propertyName, attributes | Accessor)); thisObject->structure()->setHasGetterSetterProperties(true); getterSetter->setSetter(exec->globalData(), setterFunction); @@ -531,11 +541,11 @@ double JSObject::toNumber(ExecState* exec) const return primitive.toNumber(exec); } -UString JSObject::toString(ExecState* exec) const +JSString* JSObject::toString(ExecState* exec) const { JSValue primitive = toPrimitive(exec, PreferString); if (exec->hadException()) - return ""; + return jsEmptyString(exec); return primitive.toString(exec); } @@ -646,20 +656,28 @@ void JSObject::allocatePropertyStorage(JSGlobalData& globalData, size_t oldSize, // It's important that this function not rely on structure(), since // we might be in the middle of a transition. - PropertyStorage newPropertyStorage = 0; - newPropertyStorage = new WriteBarrierBase<Unknown>[newSize]; PropertyStorage oldPropertyStorage = m_propertyStorage.get(); - ASSERT(newPropertyStorage); + PropertyStorage newPropertyStorage = 0; - for (unsigned i = 0; i < oldSize; ++i) - newPropertyStorage[i] = oldPropertyStorage[i]; + if (isUsingInlineStorage()) { + // We have this extra temp here to slake GCC's thirst for the blood of those who dereference type-punned pointers. + void* temp = newPropertyStorage; + if (!globalData.heap.tryAllocateStorage(sizeof(WriteBarrierBase<Unknown>) * newSize, &temp)) + CRASH(); + newPropertyStorage = static_cast<PropertyStorage>(temp); - if (isUsingInlineStorage()) - Heap::heap(this)->addFinalizer(this, &finalize); - else - delete [] oldPropertyStorage; + for (unsigned i = 0; i < oldSize; ++i) + newPropertyStorage[i] = oldPropertyStorage[i]; + } else { + // We have this extra temp here to slake GCC's thirst for the blood of those who dereference type-punned pointers. + void* temp = oldPropertyStorage; + if (!globalData.heap.tryReallocateStorage(&temp, sizeof(WriteBarrierBase<Unknown>) * oldSize, sizeof(WriteBarrierBase<Unknown>) * newSize)) + CRASH(); + newPropertyStorage = static_cast<PropertyStorage>(temp); + } + ASSERT(newPropertyStorage); m_propertyStorage.set(globalData, this, newPropertyStorage); } @@ -692,15 +710,11 @@ static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& p if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) { if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) { GetterSetter* accessor = GetterSetter::create(exec); - if (oldDescriptor.getter()) { - attributes |= Getter; - accessor->setGetter(exec->globalData(), asObject(oldDescriptor.getter())); - } - if (oldDescriptor.setter()) { - attributes |= Setter; - accessor->setSetter(exec->globalData(), asObject(oldDescriptor.setter())); - } - target->methodTable()->putWithAttributes(target, exec, propertyName, accessor, attributes); + if (oldDescriptor.getterPresent()) + accessor->setGetter(exec->globalData(), oldDescriptor.getterObject()); + if (oldDescriptor.setterPresent()) + accessor->setSetter(exec->globalData(), oldDescriptor.setterObject()); + target->putDirectAccessor(exec->globalData(), propertyName, accessor, attributes | Accessor); return true; } JSValue newValue = jsUndefined(); @@ -708,21 +722,32 @@ static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& p newValue = descriptor.value(); else if (oldDescriptor.value()) newValue = oldDescriptor.value(); - target->methodTable()->putWithAttributes(target, exec, propertyName, newValue, attributes & ~(Getter | Setter)); + target->putDirect(exec->globalData(), propertyName, newValue, attributes & ~Accessor); return true; } attributes &= ~ReadOnly; - if (descriptor.getter() && descriptor.getter().isObject()) - target->methodTable()->defineGetter(target, exec, propertyName, asObject(descriptor.getter()), attributes); - if (exec->hadException()) - return false; - if (descriptor.setter() && descriptor.setter().isObject()) - target->methodTable()->defineSetter(target, exec, propertyName, asObject(descriptor.setter()), attributes); - return !exec->hadException(); + GetterSetter* accessor = GetterSetter::create(exec); + + if (descriptor.getterPresent()) + accessor->setGetter(exec->globalData(), descriptor.getterObject()); + else if (oldDescriptor.getterPresent()) + accessor->setGetter(exec->globalData(), oldDescriptor.getterObject()); + if (descriptor.setterPresent()) + accessor->setSetter(exec->globalData(), descriptor.setterObject()); + else if (oldDescriptor.setterPresent()) + accessor->setSetter(exec->globalData(), oldDescriptor.setterObject()); + + target->putDirectAccessor(exec->globalData(), propertyName, accessor, attributes | Accessor); + return true; } bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException) { + // __proto__ is magic; we don't currently support setting it as a regular property. + // Silent filter out calls to set __proto__ at an early stage; pretend all is okay. + if (propertyName == exec->propertyNames().underscoreProto) + return true; + // If we have a new property we can just put it on normally PropertyDescriptor current; if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, propertyName, current)) { @@ -824,19 +849,15 @@ bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identi return false; GetterSetter* getterSetter = asGetterSetter(accessor); if (current.attributesEqual(descriptor)) { - if (descriptor.setter()) - getterSetter->setSetter(exec->globalData(), asObject(descriptor.setter())); - if (descriptor.getter()) - getterSetter->setGetter(exec->globalData(), asObject(descriptor.getter())); + if (descriptor.setterPresent()) + getterSetter->setSetter(exec->globalData(), descriptor.setterObject()); + if (descriptor.getterPresent()) + getterSetter->setGetter(exec->globalData(), descriptor.getterObject()); return true; } object->methodTable()->deleteProperty(object, exec, propertyName); unsigned attrs = current.attributesWithOverride(descriptor); - if (descriptor.setter()) - attrs |= Setter; - if (descriptor.getter()) - attrs |= Getter; - object->putDirect(exec->globalData(), propertyName, getterSetter, attrs); + object->putDirectAccessor(exec->globalData(), propertyName, getterSetter, attrs | Accessor); return true; } diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index e26012dd9..433249c20 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -55,7 +55,7 @@ namespace JSC { class Structure; struct HashTable; - JSObject* throwTypeError(ExecState*, const UString&); + JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*, const UString&); extern JS_EXPORTDATA const char* StrictModeReadonlyPropertyWriteError; // ECMA 262-3 8.6.1 @@ -66,8 +66,7 @@ namespace JSC { DontEnum = 1 << 2, // property doesn't appear in (for .. in ..) DontDelete = 1 << 3, // property can't be deleted Function = 1 << 4, // property is a function - only used by static hashtables - Getter = 1 << 5, // property is a getter - Setter = 1 << 6 // property is a setter + Accessor = 1 << 5, // property is a getter/setter }; class JSObject : public JSCell { @@ -75,18 +74,21 @@ namespace JSC { friend class JIT; friend class JSCell; friend class MarkedBlock; - friend bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot); + JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot); + + enum PutMode { + PutModePut, + PutModeDefineOwnProperty, + }; public: typedef JSCell Base; - static void destroy(JSCell*); - - static void visitChildren(JSCell*, SlotVisitor&); + JS_EXPORT_PRIVATE static void destroy(JSCell*); - static UString className(const JSObject*); + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); - static void finalize(JSCell*); + JS_EXPORT_PRIVATE static UString className(const JSObject*); JSValue prototype() const; void setPrototype(JSGlobalData&, JSValue prototype); @@ -99,43 +101,50 @@ namespace JSC { bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); - bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&); + JS_EXPORT_PRIVATE bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&); static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&); - static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); - - static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); - static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue); - - static void putWithAttributes(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); - void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue, unsigned attributes); + JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); + JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); + + JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue); + + // putDirect is effectively an unchecked vesion of 'defineOwnProperty': + // - the prototype chain is not consulted + // - accessors are not called. + // - attributes will be respected (after the call the property will exist with the given attributes) + JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); + void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes = 0); + void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&); + void putDirectWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes = 0); + void putDirectAccessor(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes); bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const; - bool hasProperty(ExecState*, const Identifier& propertyName) const; - bool hasProperty(ExecState*, unsigned propertyName) const; + JS_EXPORT_PRIVATE bool hasProperty(ExecState*, const Identifier& propertyName) const; + JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const; bool hasOwnProperty(ExecState*, const Identifier& propertyName) const; - static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName); - static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); + JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName); + JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); - static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); + JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); - static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty); + JS_EXPORT_PRIVATE static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty); - static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; - bool toBoolean(ExecState*) const; + JS_EXPORT_PRIVATE bool toBoolean(ExecState*) const; bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; - double toNumber(ExecState*) const; - UString toString(ExecState*) const; + JS_EXPORT_PRIVATE double toNumber(ExecState*) const; + JS_EXPORT_PRIVATE JSString* toString(ExecState*) const; // NOTE: JSObject and its subclasses must be able to gracefully handle ExecState* = 0, // because this call may come from inside the compiler. - static JSObject* toThisObject(JSCell*, ExecState*); + JS_EXPORT_PRIVATE static JSObject* toThisObject(JSCell*, ExecState*); JSObject* unwrappedObject(); bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const; @@ -171,35 +180,37 @@ namespace JSC { bool hasCustomProperties() { return structure()->didTransition(); } bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); } - bool putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&); - void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr = 0); - bool putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&); - - void putDirectWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr = 0); + // putOwnDataProperty has 'put' like semantics, however this method: + // - assumes the object contains no own getter/setter properties. + // - provides no special handling for __proto__ + // - does not walk the prototype chain (to check for accessors or non-writable properties). + // This is used by JSActivation. + bool putOwnDataProperty(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&); // Fast access to known property offsets. JSValue getDirectOffset(size_t offset) const { return propertyStorage()[offset].get(); } void putDirectOffset(JSGlobalData& globalData, size_t offset, JSValue value) { propertyStorage()[offset].set(globalData, this, value); } void putUndefinedAtDirectOffset(size_t offset) { propertyStorage()[offset].setUndefined(); } - void fillGetterPropertySlot(PropertySlot&, WriteBarrierBase<Unknown>* location); + JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, WriteBarrierBase<Unknown>* location); void initializeGetterSetterProperty(ExecState*, const Identifier&, GetterSetter*, unsigned attributes); - static void defineGetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes = 0); - static void defineSetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0); - JSValue lookupGetter(ExecState*, const Identifier& propertyName); - JSValue lookupSetter(ExecState*, const Identifier& propertyName); - static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow); + JS_EXPORT_PRIVATE static void defineGetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes = 0); + JS_EXPORT_PRIVATE static void defineSetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0); + JS_EXPORT_PRIVATE JSValue lookupGetter(ExecState*, const Identifier& propertyName); + JS_EXPORT_PRIVATE JSValue lookupSetter(ExecState*, const Identifier& propertyName); + JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow); bool isGlobalObject() const; bool isVariableObject() const; + bool isStaticScopeObject() const; bool isActivationObject() const; bool isErrorInstance() const; bool isGlobalThis() const; void seal(JSGlobalData&); void freeze(JSGlobalData&); - void preventExtensions(JSGlobalData&); + JS_EXPORT_PRIVATE void preventExtensions(JSGlobalData&); bool isSealed(JSGlobalData& globalData) { return structure()->isSealed(globalData); } bool isFrozen(JSGlobalData& globalData) { return structure()->isFrozen(globalData); } bool isExtensible() { return structure()->isExtensible(); } @@ -207,7 +218,7 @@ namespace JSC { bool staticFunctionsReified() { return structure()->staticFunctionsReified(); } void reifyStaticFunctionsForDelete(ExecState* exec); - void allocatePropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize); + JS_EXPORT_PRIVATE void allocatePropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize); bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage.get()) == static_cast<const void*>(this + 1); } void* addressOfPropertyStorage() @@ -281,7 +292,8 @@ namespace JSC { return &propertyStorage()[offset]; } - bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&, JSCell*); + template<PutMode> + bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*); bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); @@ -317,7 +329,7 @@ COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineSt return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } - static void destroy(JSCell*); + JS_EXPORT_PRIVATE static void destroy(JSCell*); protected: explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure) @@ -417,6 +429,11 @@ inline bool JSObject::isVariableObject() const return structure()->typeInfo().type() >= VariableObjectType; } +inline bool JSObject::isStaticScopeObject() const +{ + return structure()->typeInfo().type() == StaticScopeObjectType; +} + inline bool JSObject::isActivationObject() const { return structure()->typeInfo().type() == ActivationObjectType; @@ -628,9 +645,11 @@ inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const return jsUndefined(); } -inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction) +template<JSObject::PutMode mode> +inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot, JSCell* specificFunction) { ASSERT(value); + ASSERT(value.isGetterSetter() == !!(attributes & Accessor)); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); if (structure()->isDictionary()) { @@ -642,7 +661,7 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi // or the new value is different, then despecify. if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) structure()->despecifyDictionaryFunction(globalData, propertyName); - if (checkReadOnly && currentAttributes & ReadOnly) + if ((mode == PutModePut) && currentAttributes & ReadOnly) return false; putDirectOffset(globalData, offset, value); @@ -657,7 +676,7 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi return true; } - if (checkReadOnly && !isExtensible()) + if ((mode == PutModePut) && !isExtensible()) return false; size_t currentCapacity = structure()->propertyStorageCapacity(); @@ -693,7 +712,7 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi JSCell* currentSpecificFunction; offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction); if (offset != WTF::notFound) { - if (checkReadOnly && currentAttributes & ReadOnly) + if ((mode == PutModePut) && currentAttributes & ReadOnly) return false; // There are three possibilities here: @@ -721,7 +740,7 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi return true; } - if (checkReadOnly && !isExtensible()) + if ((mode == PutModePut) && !isExtensible()) return false; Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset); @@ -739,27 +758,31 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi return true; } -inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) +inline bool JSObject::putOwnDataProperty(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { ASSERT(value); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + ASSERT(!structure()->hasGetterSetterProperties()); - return putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, getJSFunction(value)); + return putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)); } inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) { + ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); PutPropertySlot slot; - putDirectInternal(globalData, propertyName, value, attributes, false, slot, getJSFunction(value)); + putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value)); } -inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { - return putDirectInternal(globalData, propertyName, value, 0, false, slot, getJSFunction(value)); + ASSERT(!value.isGetterSetter()); + putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, 0, slot, getJSFunction(value)); } inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) { + ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); size_t currentCapacity = structure()->propertyStorageCapacity(); size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(value)); if (currentCapacity != structure()->propertyStorageCapacity()) @@ -841,13 +864,6 @@ inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValu asCell()->methodTable()->put(asCell(), exec, propertyName, value, slot); } -inline void JSValue::putDirect(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) -{ - ASSERT(isCell() && isObject()); - if (!asObject(asCell())->putDirect(exec->globalData(), propertyName, value, slot) && slot.isStrictMode()) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); -} - inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value) { if (UNLIKELY(!isCell())) { diff --git a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp index ada921d0e..f8942b5f8 100644 --- a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp +++ b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp @@ -78,7 +78,7 @@ void JSStaticScopeObject::put(JSCell* cell, ExecState* exec, const Identifier& p ASSERT_NOT_REACHED(); } -void JSStaticScopeObject::putWithAttributes(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) +void JSStaticScopeObject::putDirectVirtual(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) { JSStaticScopeObject* thisObject = jsCast<JSStaticScopeObject*>(object); if (thisObject->symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes)) diff --git a/Source/JavaScriptCore/runtime/JSStaticScopeObject.h b/Source/JavaScriptCore/runtime/JSStaticScopeObject.h index 6a2e51a15..bbf03a347 100644 --- a/Source/JavaScriptCore/runtime/JSStaticScopeObject.h +++ b/Source/JavaScriptCore/runtime/JSStaticScopeObject.h @@ -47,7 +47,7 @@ namespace JSC{ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&); static void put(JSCell*, ExecState*, const Identifier&, JSValue, PutPropertySlot&); - static void putWithAttributes(JSObject*, ExecState*, const Identifier&, JSValue, unsigned attributes); + static void putDirectVirtual(JSObject*, ExecState*, const Identifier&, JSValue, unsigned attributes); static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(StaticScopeObjectType, StructureFlags), &s_info); } diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp index 93193b5e5..4e98f9d18 100644 --- a/Source/JavaScriptCore/runtime/JSString.cpp +++ b/Source/JavaScriptCore/runtime/JSString.cpp @@ -229,11 +229,6 @@ double JSString::toNumber(ExecState* exec) const return jsToNumber(value(exec)); } -UString JSString::toString(ExecState* exec) const -{ - return value(exec); -} - inline StringObject* StringObject::create(ExecState* exec, JSGlobalObject* globalObject, JSString* string) { StringObject* object = new (NotNull, allocateCell<StringObject>(*exec->heap())) StringObject(exec->globalData(), globalObject->stringObjectStructure()); diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index f40455571..c0637a6e0 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -214,10 +214,9 @@ namespace JSC { unsigned length() { return m_length; } JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; - bool toBoolean(ExecState*) const; + JS_EXPORT_PRIVATE bool toBoolean(ExecState*) const; bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; JSObject* toObject(ExecState*, JSGlobalObject*) const; - UString toString(ExecState*) const; double toNumber(ExecState*) const; bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); @@ -236,12 +235,12 @@ namespace JSC { static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); } static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); } - static const ClassInfo s_info; + static JS_EXPORTDATA const ClassInfo s_info; static void visitChildren(JSCell*, SlotVisitor&); private: - void resolveRope(ExecState*) const; + JS_EXPORT_PRIVATE void resolveRope(ExecState*) const; void resolveRopeSlowCase8(LChar*) const; void resolveRopeSlowCase(UChar*) const; void outOfMemory(ExecState*) const; @@ -453,24 +452,11 @@ namespace JSC { return isTrue(); // false, null, and undefined all convert to false. } - inline UString JSValue::toString(ExecState* exec) const + inline JSString* JSValue::toString(ExecState* exec) const { if (isString()) - return static_cast<JSString*>(asCell())->value(exec); - if (isInt32()) - return exec->globalData().numericStrings.add(asInt32()); - if (isDouble()) - return exec->globalData().numericStrings.add(asDouble()); - if (isTrue()) - return "true"; - if (isFalse()) - return "false"; - if (isNull()) - return "null"; - if (isUndefined()) - return "undefined"; - ASSERT(isCell()); - return asCell()->toString(exec); + return static_cast<JSString*>(asCell()); + return toStringSlowCase(exec); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp index a5d3d936a..6b803c316 100644 --- a/Source/JavaScriptCore/runtime/JSValue.cpp +++ b/Source/JavaScriptCore/runtime/JSValue.cpp @@ -204,10 +204,9 @@ bool JSValue::isValidCallee() return asObject(asCell())->globalObject(); } -JSString* JSValue::toPrimitiveString(ExecState* exec) const +JSString* JSValue::toStringSlowCase(ExecState* exec) const { - if (isString()) - return static_cast<JSString*>(asCell()); + ASSERT(!isString()); if (isInt32()) return jsString(&exec->globalData(), exec->globalData().numericStrings.add(asInt32())); if (isDouble()) @@ -222,10 +221,11 @@ JSString* JSValue::toPrimitiveString(ExecState* exec) const return jsNontrivialString(exec, exec->propertyNames().undefined.ustring()); ASSERT(isCell()); - JSValue v = asCell()->toPrimitive(exec, NoPreference); - if (v.isString()) - return static_cast<JSString*>(v.asCell()); - return jsString(&exec->globalData(), v.toString(exec)); + JSValue value = asCell()->toPrimitive(exec, PreferString); + if (exec->hadException()) + return jsEmptyString(exec); + ASSERT(!value.isObject()); + return value.toString(exec); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h index a00106274..79e50fba0 100644 --- a/Source/JavaScriptCore/runtime/JSValue.h +++ b/Source/JavaScriptCore/runtime/JSValue.h @@ -93,7 +93,7 @@ namespace JSC { }; // This implements ToInt32, defined in ECMA-262 9.5. - int32_t toInt32(double); + JS_EXPORT_PRIVATE int32_t toInt32(double); // This implements ToUInt32, defined in ECMA-262 9.6. inline uint32_t toUInt32(double number) @@ -197,13 +197,12 @@ namespace JSC { // toNumber conversion is expected to be side effect free if an exception has // been set in the ExecState already. double toNumber(ExecState*) const; - UString toString(ExecState*) const; - JSString* toPrimitiveString(ExecState*) const; + JSString* toString(ExecState*) const; JSObject* toObject(ExecState*) const; JSObject* toObject(ExecState*, JSGlobalObject*) const; // Integer conversions. - double toInteger(ExecState*) const; + JS_EXPORT_PRIVATE double toInteger(ExecState*) const; double toIntegerPreserveNaN(ExecState*) const; int32_t toInt32(ExecState*) const; uint32_t toUInt32(ExecState*) const; @@ -218,7 +217,6 @@ namespace JSC { JSValue get(ExecState*, unsigned propertyName) const; JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const; void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); - void putDirect(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); void put(ExecState*, unsigned propertyName, JSValue); JSObject* toThisObject(ExecState*) const; @@ -232,7 +230,7 @@ namespace JSC { bool isCell() const; JSCell* asCell() const; - bool isValidCallee(); + JS_EXPORT_PRIVATE bool isValidCallee(); #ifndef NDEBUG char* description(); @@ -245,11 +243,12 @@ namespace JSC { JSValue(HashTableDeletedValueTag); inline const JSValue asValue() const { return *this; } - double toNumberSlowCase(ExecState*) const; - JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const; - JSObject* toThisObjectSlowCase(ExecState*) const; + JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const; + JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*) const; + JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const; + JS_EXPORT_PRIVATE JSObject* toThisObjectSlowCase(ExecState*) const; - JSObject* synthesizePrototype(ExecState*) const; + JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const; JSObject* synthesizeObject(ExecState*) const; #if USE(JSVALUE32_64) diff --git a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h b/Source/JavaScriptCore/runtime/JSValueInlineMethods.h index e13d34745..1373558f7 100644 --- a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h +++ b/Source/JavaScriptCore/runtime/JSValueInlineMethods.h @@ -477,6 +477,7 @@ namespace JSC { inline double JSValue::asDouble() const { + ASSERT(isDouble()); return reinterpretIntptrToDouble(u.asInt64 - DoubleEncodeOffset); } diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.cpp b/Source/JavaScriptCore/runtime/JSVariableObject.cpp index 706e3debb..8ca695074 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSVariableObject.cpp @@ -73,7 +73,7 @@ bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertyDe return false; } -void JSVariableObject::putWithAttributes(JSObject*, ExecState*, const Identifier&, JSValue, unsigned) +void JSVariableObject::putDirectVirtual(JSObject*, ExecState*, const Identifier&, JSValue, unsigned) { ASSERT_NOT_REACHED(); } diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.h b/Source/JavaScriptCore/runtime/JSVariableObject.h index 78e624e02..c1d05ff74 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.h +++ b/Source/JavaScriptCore/runtime/JSVariableObject.h @@ -48,12 +48,12 @@ namespace JSC { SymbolTable& symbolTable() const { return *m_symbolTable; } - static void destroy(JSCell*); + JS_EXPORT_PRIVATE static void destroy(JSCell*); - static NO_RETURN_DUE_TO_ASSERT void putWithAttributes(JSObject*, ExecState*, const Identifier&, JSValue, unsigned attributes); + static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, const Identifier&, JSValue, unsigned attributes); - static bool deleteProperty(JSCell*, ExecState*, const Identifier&); - static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, const Identifier&); + JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); bool isDynamicScope(bool& requiresDynamicChecks) const; @@ -88,7 +88,7 @@ namespace JSC { void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray); bool symbolTableGet(const Identifier&, PropertySlot&); - bool symbolTableGet(const Identifier&, PropertyDescriptor&); + JS_EXPORT_PRIVATE bool symbolTableGet(const Identifier&, PropertyDescriptor&); bool symbolTableGet(const Identifier&, PropertySlot&, bool& slotIsWriteable); bool symbolTablePut(ExecState*, const Identifier&, JSValue, bool shouldThrow); bool symbolTablePutWithAttributes(JSGlobalData&, const Identifier&, JSValue, unsigned attributes); diff --git a/Source/JavaScriptCore/runtime/Lookup.h b/Source/JavaScriptCore/runtime/Lookup.h index 8ed70b41d..64d06b503 100644 --- a/Source/JavaScriptCore/runtime/Lookup.h +++ b/Source/JavaScriptCore/runtime/Lookup.h @@ -126,7 +126,7 @@ namespace JSC { createTable(&exec->globalData()); } - void deleteTable() const; + JS_EXPORT_PRIVATE void deleteTable() const; // Find an entry in the table, and return the entry. ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const @@ -218,10 +218,10 @@ namespace JSC { } // Convert the hash table keys to identifiers. - void createTable(JSGlobalData*) const; + JS_EXPORT_PRIVATE void createTable(JSGlobalData*) const; }; - bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&); + JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&); /** * This method does it all (looking in the hashtable, checking for function diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.h b/Source/JavaScriptCore/runtime/MemoryStatistics.h index d4b8b6fc1..9a86df296 100644 --- a/Source/JavaScriptCore/runtime/MemoryStatistics.h +++ b/Source/JavaScriptCore/runtime/MemoryStatistics.h @@ -37,7 +37,7 @@ struct GlobalMemoryStatistics { size_t JITBytes; }; -GlobalMemoryStatistics globalMemoryStatistics(); +JS_EXPORT_PRIVATE GlobalMemoryStatistics globalMemoryStatistics(); } diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.cpp b/Source/JavaScriptCore/runtime/NumberPrototype.cpp index 4612b56d2..fb90bcd17 100644 --- a/Source/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NumberPrototype.cpp @@ -447,7 +447,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec) radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0 if (radix == 10) - return JSValue::encode(jsString(exec, jsNumber(x).toString(exec))); + return JSValue::encode(jsNumber(x).toString(exec)); // Fast path for number to character conversion. if (radix == 36) { @@ -474,7 +474,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec) if (!toThisNumber(exec->hostThisValue(), x)) return throwVMTypeError(exec); - return JSValue::encode(jsString(exec, jsNumber(x).toString(exec))); + return JSValue::encode(jsNumber(x).toString(exec)); } EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec) diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp index 65d28c18c..d96c1de7f 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -149,7 +149,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState { if (!exec->argument(0).isObject()) return throwVMError(exec, createTypeError(exec, "Requested property descriptor of a value that is not an object.")); - UString propertyName = exec->argument(1).toString(exec); + UString propertyName = exec->argument(1).toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsNull()); JSObject* object = asObject(exec->argument(0)); @@ -164,8 +164,10 @@ EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState description->putDirect(exec->globalData(), exec->propertyNames().value, descriptor.value() ? descriptor.value() : jsUndefined(), 0); description->putDirect(exec->globalData(), exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0); } else { - description->putDirect(exec->globalData(), exec->propertyNames().get, descriptor.getter() ? descriptor.getter() : jsUndefined(), 0); - description->putDirect(exec->globalData(), exec->propertyNames().set, descriptor.setter() ? descriptor.setter() : jsUndefined(), 0); + ASSERT(descriptor.getter()); + ASSERT(descriptor.setter()); + description->putDirect(exec->globalData(), exec->propertyNames().get, descriptor.getter(), 0); + description->putDirect(exec->globalData(), exec->propertyNames().set, descriptor.setter(), 0); } description->putDirect(exec->globalData(), exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0); @@ -251,8 +253,7 @@ static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor throwError(exec, createTypeError(exec, "Getter must be a function.")); return false; } - } else - get = JSValue(); + } desc.setGetter(get); } @@ -267,9 +268,7 @@ static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor throwError(exec, createTypeError(exec, "Setter must be a function.")); return false; } - } else - set = JSValue(); - + } desc.setSetter(set); } @@ -293,13 +292,13 @@ EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec) if (!exec->argument(0).isObject()) return throwVMError(exec, createTypeError(exec, "Properties can only be defined on Objects.")); JSObject* O = asObject(exec->argument(0)); - UString propertyName = exec->argument(1).toString(exec); + UString propertyName = exec->argument(1).toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsNull()); PropertyDescriptor descriptor; if (!toPropertyDescriptor(exec, exec->argument(2), descriptor)) return JSValue::encode(jsNull()); - ASSERT((descriptor.attributes() & (Getter | Setter)) || (!descriptor.isAccessorDescriptor())); + ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor())); ASSERT(!exec->hadException()); O->methodTable()->defineOwnProperty(O, exec, Identifier(exec, propertyName), descriptor, true); return JSValue::encode(O); diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp index 3f4dc19db..7ca7dae61 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -118,7 +118,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState* exec) EncodedJSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - return JSValue::encode(jsBoolean(thisValue.toObject(exec)->hasOwnProperty(exec, Identifier(exec, exec->argument(0).toString(exec))))); + return JSValue::encode(jsBoolean(thisValue.toObject(exec)->hasOwnProperty(exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec))))); } EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec) @@ -149,7 +149,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec) CallData callData; if (getCallData(exec->argument(1), callData) == CallTypeNone) return throwVMError(exec, createSyntaxError(exec, "invalid getter usage")); - thisObject->methodTable()->defineGetter(thisObject, exec, Identifier(exec, exec->argument(0).toString(exec)), asObject(exec->argument(1)), 0); + thisObject->methodTable()->defineGetter(thisObject, exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)), asObject(exec->argument(1)), 0); return JSValue::encode(jsUndefined()); } @@ -162,7 +162,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec) CallData callData; if (getCallData(exec->argument(1), callData) == CallTypeNone) return throwVMError(exec, createSyntaxError(exec, "invalid setter usage")); - thisObject->methodTable()->defineSetter(thisObject, exec, Identifier(exec, exec->argument(0).toString(exec)), asObject(exec->argument(1)), 0); + thisObject->methodTable()->defineSetter(thisObject, exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)), asObject(exec->argument(1)), 0); return JSValue::encode(jsUndefined()); } @@ -172,7 +172,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState* exec) if (exec->hadException()) return JSValue::encode(jsUndefined()); - return JSValue::encode(thisObject->lookupGetter(exec, Identifier(exec, exec->argument(0).toString(exec)))); + return JSValue::encode(thisObject->lookupGetter(exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)))); } EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec) @@ -181,13 +181,13 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec) if (exec->hadException()) return JSValue::encode(jsUndefined()); - return JSValue::encode(thisObject->lookupSetter(exec, Identifier(exec, exec->argument(0).toString(exec)))); + return JSValue::encode(thisObject->lookupSetter(exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)))); } EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - return JSValue::encode(jsBoolean(thisValue.toObject(exec)->propertyIsEnumerable(exec, Identifier(exec, exec->argument(0).toString(exec))))); + return JSValue::encode(jsBoolean(thisValue.toObject(exec)->propertyIsEnumerable(exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec))))); } // 15.2.4.3 Object.prototype.toLocaleString() diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.h b/Source/JavaScriptCore/runtime/ObjectPrototype.h index 78b1cbd39..4c49e97a7 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.h +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.h @@ -59,7 +59,7 @@ namespace JSC { bool m_hasNoPropertiesWithUInt32Names; }; - EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*); + JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Operations.cpp b/Source/JavaScriptCore/runtime/Operations.cpp index b89746f3f..459feb466 100644 --- a/Source/JavaScriptCore/runtime/Operations.cpp +++ b/Source/JavaScriptCore/runtime/Operations.cpp @@ -47,13 +47,11 @@ NEVER_INLINE JSValue jsAddSlowCase(CallFrame* callFrame, JSValue v1, JSValue v2) JSValue p1 = v1.toPrimitive(callFrame); JSValue p2 = v2.toPrimitive(callFrame); - if (p1.isString()) { - return p2.isString() - ? jsString(callFrame, asString(p1), asString(p2)) - : jsString(callFrame, asString(p1), jsString(callFrame, p2.toString(callFrame))); - } + if (p1.isString()) + return jsString(callFrame, asString(p1), p2.toString(callFrame)); + if (p2.isString()) - return jsString(callFrame, jsString(callFrame, p1.toString(callFrame)), asString(p2)); + return jsString(callFrame, p1.toString(callFrame), asString(p2)); return jsNumber(p1.toNumber(callFrame) + p2.toNumber(callFrame)); } diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h index ca2174fa1..945283899 100644 --- a/Source/JavaScriptCore/runtime/Operations.h +++ b/Source/JavaScriptCore/runtime/Operations.h @@ -81,10 +81,7 @@ namespace JSC { for (unsigned i = 0; i < count; ++i) { JSValue v = strings[i].jsValue(); - if (v.isString()) - ropeBuilder.append(asString(v)); - else - ropeBuilder.append(jsString(globalData, v.toString(exec))); + ropeBuilder.append(v.toString(exec)); if (ropeBuilder.length() < oldLength) // True for overflow return throwOutOfMemoryError(exec); @@ -97,20 +94,13 @@ namespace JSC { { JSGlobalData* globalData = &exec->globalData(); JSString::RopeBuilder ropeBuilder(*globalData); - - if (thisValue.isString()) - ropeBuilder.append(asString(thisValue)); - else - ropeBuilder.append(jsString(globalData, thisValue.toString(exec))); + ropeBuilder.append(thisValue.toString(exec)); unsigned oldLength = 0; for (unsigned i = 0; i < exec->argumentCount(); ++i) { JSValue v = exec->argument(i); - if (v.isString()) - ropeBuilder.append(asString(v)); - else - ropeBuilder.append(jsString(globalData, v.toString(exec))); + ropeBuilder.append(v.toString(exec)); if (ropeBuilder.length() < oldLength) // True for overflow return throwOutOfMemoryError(exec); @@ -300,11 +290,8 @@ namespace JSC { if (v1.isNumber() && v2.isNumber()) return jsNumber(v1.asNumber() + v2.asNumber()); - if (v1.isString()) { - return v2.isString() - ? jsString(callFrame, asString(v1), asString(v2)) - : jsString(callFrame, asString(v1), v2.toPrimitiveString(callFrame)); - } + if (v1.isString() && !v2.isObject()) + return jsString(callFrame, asString(v1), v2.toString(callFrame)); // All other cases are pretty uncommon return jsAddSlowCase(callFrame, v1, v2); diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp index 68d10b7bd..ddfba6e7c 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -27,6 +27,7 @@ #include "Options.h" #include <limits> +#include <wtf/NumberOfCores.h> #include <wtf/PageBlock.h> #if OS(DARWIN) && ENABLE(PARALLEL_GC) @@ -129,10 +130,10 @@ void setHeuristic(T& variable, const char* name, U value) void initializeOptions() { - SET(maximumOptimizationCandidateInstructionCount, 1000); + SET(maximumOptimizationCandidateInstructionCount, 1100); - SET(maximumFunctionForCallInlineCandidateInstructionCount, 150); - SET(maximumFunctionForConstructInlineCandidateInstructionCount, 80); + SET(maximumFunctionForCallInlineCandidateInstructionCount, 180); + SET(maximumFunctionForConstructInlineCandidateInstructionCount, 100); SET(maximumInliningDepth, 5); @@ -174,12 +175,8 @@ void initializeOptions() SET(opaqueRootMergeThreshold, 1000); int cpusToUse = 1; -#if OS(DARWIN) && ENABLE(PARALLEL_GC) - int name[2]; - size_t valueSize = sizeof(cpusToUse); - name[0] = CTL_HW; - name[1] = HW_AVAILCPU; - sysctl(name, 2, &cpusToUse, &valueSize, 0, 0); +#if ENABLE(PARALLEL_GC) + cpusToUse = WTF::numberOfProcessorCores(); #endif // We don't scale so well beyond 4. if (cpusToUse > 4) diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h index f7cc5f4e8..feebd37bb 100644 --- a/Source/JavaScriptCore/runtime/Options.h +++ b/Source/JavaScriptCore/runtime/Options.h @@ -73,8 +73,8 @@ extern unsigned gcMarkStackSegmentSize; extern unsigned minimumNumberOfCellsToKeep; extern unsigned maximumNumberOfSharedSegments; extern unsigned sharedStackWakeupThreshold; -extern unsigned numberOfGCMarkers; -extern unsigned opaqueRootMergeThreshold; +JS_EXPORTDATA extern unsigned numberOfGCMarkers; +JS_EXPORTDATA extern unsigned opaqueRootMergeThreshold; void initializeOptions(); diff --git a/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp index c664952a5..e3458e4b9 100644 --- a/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp +++ b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp @@ -84,24 +84,31 @@ JSValue PropertyDescriptor::setter() const return m_setter; } +JSObject* PropertyDescriptor::getterObject() const +{ + ASSERT(isAccessorDescriptor() && getterPresent()); + return m_getter.isObject() ? asObject(m_getter) : 0; +} + +JSObject* PropertyDescriptor::setterObject() const +{ + ASSERT(isAccessorDescriptor() && setterPresent()); + return m_setter.isObject() ? asObject(m_setter) : 0; +} + void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes) { ASSERT(value); + ASSERT(value.isGetterSetter() == !!(attributes & Accessor)); + m_attributes = attributes; if (value.isGetterSetter()) { - GetterSetter* accessor = asGetterSetter(value); - - m_getter = accessor->getter(); - if (m_getter) - m_attributes |= Getter; + m_attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this! - m_setter = accessor->setter(); - if (m_setter) - m_attributes |= Setter; - - ASSERT(m_getter || m_setter); + GetterSetter* accessor = asGetterSetter(value); + m_getter = accessor->getter() ? accessor->getter() : jsUndefined(); + m_setter = accessor->setter() ? accessor->setter() : jsUndefined(); m_seenAttributes = EnumerablePresent | ConfigurablePresent; - m_attributes &= ~ReadOnly; } else { m_value = value; m_seenAttributes = EnumerablePresent | ConfigurablePresent | WritablePresent; @@ -110,14 +117,12 @@ void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes) void PropertyDescriptor::setAccessorDescriptor(GetterSetter* accessor, unsigned attributes) { - ASSERT(attributes & (Getter | Setter)); - ASSERT(accessor->getter() || accessor->setter()); - ASSERT(!accessor->getter() == !(attributes & Getter)); - ASSERT(!accessor->setter() == !(attributes & Setter)); + ASSERT(attributes & Accessor); + attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this! + m_attributes = attributes; - m_getter = accessor->getter(); - m_setter = accessor->setter(); - m_attributes &= ~ReadOnly; + m_getter = accessor->getter() ? accessor->getter() : jsUndefined(); + m_setter = accessor->setter() ? accessor->setter() : jsUndefined(); m_seenAttributes = EnumerablePresent | ConfigurablePresent; } @@ -151,14 +156,14 @@ void PropertyDescriptor::setConfigurable(bool configurable) void PropertyDescriptor::setSetter(JSValue setter) { m_setter = setter; - m_attributes |= Setter; + m_attributes |= Accessor; m_attributes &= ~ReadOnly; } void PropertyDescriptor::setGetter(JSValue getter) { m_getter = getter; - m_attributes |= Getter; + m_attributes |= Accessor; m_attributes &= ~ReadOnly; } @@ -217,6 +222,7 @@ unsigned PropertyDescriptor::attributesWithOverride(const PropertyDescriptor& ot unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescriptor& current) const { + unsigned currentAttributes = current.m_attributes; unsigned overrideMask = 0; if (writablePresent()) overrideMask |= ReadOnly; @@ -225,8 +231,8 @@ unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescripto if (configurablePresent()) overrideMask |= DontDelete; if (isAccessorDescriptor()) - overrideMask |= (Getter | Setter); - return (m_attributes & overrideMask) | (current.m_attributes & ~overrideMask); + overrideMask |= Accessor; + return (m_attributes & overrideMask) | (currentAttributes & ~overrideMask); } } diff --git a/Source/JavaScriptCore/runtime/PropertyDescriptor.h b/Source/JavaScriptCore/runtime/PropertyDescriptor.h index 3d481b25e..98af02e66 100644 --- a/Source/JavaScriptCore/runtime/PropertyDescriptor.h +++ b/Source/JavaScriptCore/runtime/PropertyDescriptor.h @@ -41,25 +41,27 @@ namespace JSC { , m_seenAttributes(0) { } - bool writable() const; - bool enumerable() const; - bool configurable() const; - bool isDataDescriptor() const; + JS_EXPORT_PRIVATE bool writable() const; + JS_EXPORT_PRIVATE bool enumerable() const; + JS_EXPORT_PRIVATE bool configurable() const; + JS_EXPORT_PRIVATE bool isDataDescriptor() const; bool isGenericDescriptor() const; - bool isAccessorDescriptor() const; + JS_EXPORT_PRIVATE bool isAccessorDescriptor() const; unsigned attributes() const { return m_attributes; } JSValue value() const { return m_value; } - JSValue getter() const; - JSValue setter() const; - void setUndefined(); - void setDescriptor(JSValue value, unsigned attributes); + JS_EXPORT_PRIVATE JSValue getter() const; + JS_EXPORT_PRIVATE JSValue setter() const; + JSObject* getterObject() const; + JSObject* setterObject() const; + JS_EXPORT_PRIVATE void setUndefined(); + JS_EXPORT_PRIVATE void setDescriptor(JSValue value, unsigned attributes); void setAccessorDescriptor(GetterSetter* accessor, unsigned attributes); - void setWritable(bool); - void setEnumerable(bool); - void setConfigurable(bool); + JS_EXPORT_PRIVATE void setWritable(bool); + JS_EXPORT_PRIVATE void setEnumerable(bool); + JS_EXPORT_PRIVATE void setConfigurable(bool); void setValue(JSValue value) { m_value = value; } - void setSetter(JSValue); - void setGetter(JSValue); + JS_EXPORT_PRIVATE void setSetter(JSValue); + JS_EXPORT_PRIVATE void setGetter(JSValue); bool isEmpty() const { return !(m_value || m_getter || m_setter || m_seenAttributes); } bool writablePresent() const { return m_seenAttributes & WritablePresent; } bool enumerablePresent() const { return m_seenAttributes & EnumerablePresent; } @@ -72,7 +74,7 @@ namespace JSC { unsigned attributesOverridingCurrent(const PropertyDescriptor& current) const; private: - static unsigned defaultAttributes; + JS_EXPORTDATA static unsigned defaultAttributes; bool operator==(const PropertyDescriptor&){ return false; } enum { WritablePresent = 1, EnumerablePresent = 2, ConfigurablePresent = 4}; // May be a getter/setter diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.h b/Source/JavaScriptCore/runtime/PropertyNameArray.h index 0da930f17..dabda945b 100644 --- a/Source/JavaScriptCore/runtime/PropertyNameArray.h +++ b/Source/JavaScriptCore/runtime/PropertyNameArray.h @@ -69,7 +69,7 @@ namespace JSC { JSGlobalData* globalData() { return m_globalData; } void add(const Identifier& identifier) { add(identifier.impl()); } - void add(StringImpl*); + JS_EXPORT_PRIVATE void add(StringImpl*); void addKnownUnique(StringImpl* identifier) { m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); } Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; } diff --git a/Source/JavaScriptCore/runtime/PropertySlot.h b/Source/JavaScriptCore/runtime/PropertySlot.h index 8557e6d24..cfedf7876 100644 --- a/Source/JavaScriptCore/runtime/PropertySlot.h +++ b/Source/JavaScriptCore/runtime/PropertySlot.h @@ -218,7 +218,7 @@ namespace JSC { return m_getValue; } private: - JSValue functionGetter(ExecState*) const; + JS_EXPORT_PRIVATE JSValue functionGetter(ExecState*) const; GetValueFunc m_getValue; GetIndexValueFunc m_getIndexValue; diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp index 0d513d2cc..69bca5df0 100644 --- a/Source/JavaScriptCore/runtime/RegExp.cpp +++ b/Source/JavaScriptCore/runtime/RegExp.cpp @@ -330,68 +330,52 @@ void RegExp::compileIfNecessary(JSGlobalData& globalData, Yarr::YarrCharSize cha compile(&globalData, charSize); } - -int RegExp::match(JSGlobalData& globalData, const UString& s, int startOffset, Vector<int, 32>* ovector) +int RegExp::match(JSGlobalData& globalData, const UString& s, unsigned startOffset, Vector<int, 32>* ovector) { - if (startOffset < 0) - startOffset = 0; - #if ENABLE(REGEXP_TRACING) m_rtMatchCallCount++; #endif - if (static_cast<unsigned>(startOffset) > s.length() || s.isNull()) - return -1; - - if (m_state != ParseError) { - compileIfNecessary(globalData, s.is8Bit() ? Yarr::Char8 : Yarr::Char16); - - int offsetVectorSize = (m_numSubpatterns + 1) * 2; - int* offsetVector; - Vector<int, 32> nonReturnedOvector; - if (ovector) { - ovector->resize(offsetVectorSize); - offsetVector = ovector->data(); - } else { - nonReturnedOvector.resize(offsetVectorSize); - offsetVector = nonReturnedOvector.data(); - } + ASSERT(m_state != ParseError); + compileIfNecessary(globalData, s.is8Bit() ? Yarr::Char8 : Yarr::Char16); - ASSERT(offsetVector); - // Initialize offsetVector with the return value (index 0) and the - // first subpattern start indicies (even index values) set to -1. - // No need to init the subpattern end indicies. - for (unsigned j = 0, i = 0; i < m_numSubpatterns + 1; j += 2, i++) - offsetVector[j] = -1; + int offsetVectorSize = (m_numSubpatterns + 1) * 2; + int* offsetVector; + Vector<int, 32> nonReturnedOvector; + if (ovector) { + ovector->resize(offsetVectorSize); + offsetVector = ovector->data(); + } else { + nonReturnedOvector.resize(offsetVectorSize); + offsetVector = nonReturnedOvector.data(); + } + ASSERT(offsetVector); - int result; + int result; #if ENABLE(YARR_JIT) - if (m_state == JITCode) { - if (s.is8Bit()) - result = Yarr::execute(m_representation->m_regExpJITCode, s.characters8(), startOffset, s.length(), offsetVector); - else - result = Yarr::execute(m_representation->m_regExpJITCode, s.characters16(), startOffset, s.length(), offsetVector); + if (m_state == JITCode) { + if (s.is8Bit()) + result = Yarr::execute(m_representation->m_regExpJITCode, s.characters8(), startOffset, s.length(), offsetVector); + else + result = Yarr::execute(m_representation->m_regExpJITCode, s.characters16(), startOffset, s.length(), offsetVector); #if ENABLE(YARR_JIT_DEBUG) - matchCompareWithInterpreter(s, startOffset, offsetVector, result); + matchCompareWithInterpreter(s, startOffset, offsetVector, result); #endif - } else + } else #endif - result = Yarr::interpret(m_representation->m_regExpBytecode.get(), s, startOffset, s.length(), offsetVector); - ASSERT(result >= -1); + result = Yarr::interpret(m_representation->m_regExpBytecode.get(), s, startOffset, s.length(), offsetVector); + ASSERT(result >= -1); #if REGEXP_FUNC_TEST_DATA_GEN - RegExpFunctionalTestCollector::get()->outputOneTest(this, s, startOffset, offsetVector, result); + RegExpFunctionalTestCollector::get()->outputOneTest(this, s, startOffset, offsetVector, result); #endif #if ENABLE(REGEXP_TRACING) - if (result != -1) - m_rtMatchFoundCount++; + if (result != -1) + m_rtMatchFoundCount++; #endif - return result; - } - - return -1; + return result; } void RegExp::invalidateCode() diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h index 65eb48499..d0201cbfb 100644 --- a/Source/JavaScriptCore/runtime/RegExp.h +++ b/Source/JavaScriptCore/runtime/RegExp.h @@ -35,13 +35,13 @@ namespace JSC { struct RegExpRepresentation; class JSGlobalData; - RegExpFlags regExpFlags(const UString&); + JS_EXPORT_PRIVATE RegExpFlags regExpFlags(const UString&); class RegExp : public JSCell { public: typedef JSCell Base; - static RegExp* create(JSGlobalData&, const UString& pattern, RegExpFlags); + JS_EXPORT_PRIVATE static RegExp* create(JSGlobalData&, const UString& pattern, RegExpFlags); static void destroy(JSCell*); bool global() const { return m_flags & FlagGlobal; } @@ -53,7 +53,7 @@ namespace JSC { bool isValid() const { return !m_constructionError && m_flags != InvalidFlags; } const char* errorMessage() const { return m_constructionError; } - int match(JSGlobalData&, const UString&, int startOffset, Vector<int, 32>* ovector = 0); + JS_EXPORT_PRIVATE int match(JSGlobalData&, const UString&, unsigned startOffset, Vector<int, 32>* ovector = 0); unsigned numSubpatterns() const { return m_numSubpatterns; } bool hasCode() @@ -72,7 +72,7 @@ namespace JSC { return Structure::create(globalData, globalObject, prototype, TypeInfo(LeafType, 0), &s_info); } - static JS_EXPORTDATA const ClassInfo s_info; + static const ClassInfo s_info; RegExpKey key() { return RegExpKey(m_flags, m_patternString); } diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp index 05832ed0c..53e880e70 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -97,9 +97,18 @@ const ClassInfo RegExpMatchesArray::s_info = {"Array", &JSArray::s_info, 0, 0, C @end */ +RegExpResult& RegExpResult::operator=(const RegExpConstructorPrivate& rhs) +{ + this->input = rhs.input; + this->ovector = rhs.lastOvector(); + this->lastNumSubPatterns = rhs.lastNumSubPatterns; + + return *this; +} + + RegExpConstructor::RegExpConstructor(JSGlobalObject* globalObject, Structure* structure) : InternalFunction(globalObject, structure) - , d(adoptPtr(new RegExpConstructorPrivate)) { } @@ -122,27 +131,14 @@ void RegExpConstructor::destroy(JSCell* cell) RegExpMatchesArray::RegExpMatchesArray(ExecState* exec) : JSArray(exec->globalData(), exec->lexicalGlobalObject()->regExpMatchesArrayStructure()) + , m_didFillArrayInstance(false) { } -void RegExpMatchesArray::finishCreation(JSGlobalData& globalData, RegExpConstructorPrivate* data) +void RegExpMatchesArray::finishCreation(JSGlobalData& globalData, const RegExpConstructorPrivate& data) { - Base::finishCreation(globalData, data->lastNumSubPatterns + 1); - RegExpConstructorPrivate* d = new RegExpConstructorPrivate; - d->input = data->lastInput; - d->lastInput = data->lastInput; - d->lastNumSubPatterns = data->lastNumSubPatterns; - unsigned offsetVectorSize = (data->lastNumSubPatterns + 1) * 2; // only copying the result part of the vector - d->lastOvector().resize(offsetVectorSize); - memcpy(d->lastOvector().data(), data->lastOvector().data(), offsetVectorSize * sizeof(int)); - // d->multiline is not needed, and remains uninitialized - - setSubclassData(d); -} - -RegExpMatchesArray::~RegExpMatchesArray() -{ - delete static_cast<RegExpConstructorPrivate*>(subclassData()); + Base::finishCreation(globalData, data.lastNumSubPatterns + 1); + m_regExpResult = data; } void RegExpMatchesArray::destroy(JSCell* cell) @@ -152,65 +148,61 @@ void RegExpMatchesArray::destroy(JSCell* cell) void RegExpMatchesArray::fillArrayInstance(ExecState* exec) { - RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(subclassData()); - ASSERT(d); - - unsigned lastNumSubpatterns = d->lastNumSubPatterns; + unsigned lastNumSubpatterns = m_regExpResult.lastNumSubPatterns; for (unsigned i = 0; i <= lastNumSubpatterns; ++i) { - int start = d->lastOvector()[2 * i]; + int start = m_regExpResult.ovector[2 * i]; if (start >= 0) - JSArray::putByIndex(this, exec, i, jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start)); + JSArray::putByIndex(this, exec, i, jsSubstring(exec, m_regExpResult.input, start, m_regExpResult.ovector[2 * i + 1] - start)); else JSArray::putByIndex(this, exec, i, jsUndefined()); } PutPropertySlot slot; - JSArray::put(this, exec, exec->propertyNames().index, jsNumber(d->lastOvector()[0]), slot); - JSArray::put(this, exec, exec->propertyNames().input, jsString(exec, d->input), slot); + JSArray::put(this, exec, exec->propertyNames().index, jsNumber(m_regExpResult.ovector[0]), slot); + JSArray::put(this, exec, exec->propertyNames().input, jsString(exec, m_regExpResult.input), slot); - delete d; - setSubclassData(0); + m_didFillArrayInstance = true; } JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const { - return RegExpMatchesArray::create(exec, d.get()); + return RegExpMatchesArray::create(exec, d); } JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) const { - if (!d->lastOvector().isEmpty() && i <= d->lastNumSubPatterns) { - int start = d->lastOvector()[2 * i]; + if (!d.lastOvector().isEmpty() && i <= d.lastNumSubPatterns) { + int start = d.lastOvector()[2 * i]; if (start >= 0) - return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start); + return jsSubstring(exec, d.lastInput, start, d.lastOvector()[2 * i + 1] - start); } return jsEmptyString(exec); } JSValue RegExpConstructor::getLastParen(ExecState* exec) const { - unsigned i = d->lastNumSubPatterns; + unsigned i = d.lastNumSubPatterns; if (i > 0) { - ASSERT(!d->lastOvector().isEmpty()); - int start = d->lastOvector()[2 * i]; + ASSERT(!d.lastOvector().isEmpty()); + int start = d.lastOvector()[2 * i]; if (start >= 0) - return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start); + return jsSubstring(exec, d.lastInput, start, d.lastOvector()[2 * i + 1] - start); } return jsEmptyString(exec); } JSValue RegExpConstructor::getLeftContext(ExecState* exec) const { - if (!d->lastOvector().isEmpty()) - return jsSubstring(exec, d->lastInput, 0, d->lastOvector()[0]); + if (!d.lastOvector().isEmpty()) + return jsSubstring(exec, d.lastInput, 0, d.lastOvector()[0]); return jsEmptyString(exec); } JSValue RegExpConstructor::getRightContext(ExecState* exec) const { - if (!d->lastOvector().isEmpty()) - return jsSubstring(exec, d->lastInput, d->lastOvector()[1], d->lastInput.length() - d->lastOvector()[1]); + if (!d.lastOvector().isEmpty()) + return jsSubstring(exec, d.lastInput, d.lastOvector()[1], d.lastInput.length() - d.lastOvector()[1]); return jsEmptyString(exec); } @@ -306,7 +298,7 @@ void RegExpConstructor::put(JSCell* cell, ExecState* exec, const Identifier& pro void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValue value) { - asRegExpConstructor(baseObject)->setInput(value.toString(exec)); + asRegExpConstructor(baseObject)->setInput(value.toString(exec)->value(exec)); } void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValue value) @@ -331,13 +323,13 @@ JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const A return asObject(arg0); } - UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec); + UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec)->value(exec); if (exec->hadException()) return 0; RegExpFlags flags = NoFlags; if (!arg1.isUndefined()) { - flags = regExpFlags(arg1.toString(exec)); + flags = regExpFlags(arg1.toString(exec)->value(exec)); if (exec->hadException()) return 0; if (flags == InvalidFlags) @@ -377,24 +369,24 @@ CallType RegExpConstructor::getCallData(JSCell*, CallData& callData) void RegExpConstructor::setInput(const UString& input) { - d->input = input; + d.input = input; } const UString& RegExpConstructor::input() const { // Can detect a distinct initial state that is invisible to JavaScript, by checking for null // state (since jsString turns null strings to empty strings). - return d->input; + return d.input; } void RegExpConstructor::setMultiline(bool multiline) { - d->multiline = multiline; + d.multiline = multiline; } bool RegExpConstructor::multiline() const { - return d->multiline; + return d.multiline; } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.h b/Source/JavaScriptCore/runtime/RegExpConstructor.h index 0a43da70a..08a96b544 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.h +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.h @@ -55,6 +55,21 @@ namespace JSC { unsigned lastOvectorIndex : 1; }; + struct RegExpResult { + WTF_MAKE_FAST_ALLOCATED; + public: + RegExpResult() + : lastNumSubPatterns(0) + { + } + + RegExpResult& operator=(const RegExpConstructorPrivate&); + + UString input; + unsigned lastNumSubPatterns; + Vector<int, 32> ovector; + }; + class RegExpConstructor : public InternalFunction { public: typedef InternalFunction Base; @@ -102,7 +117,7 @@ namespace JSC { static ConstructType getConstructData(JSCell*, ConstructData&); static CallType getCallData(JSCell*, CallData&); - OwnPtr<RegExpConstructorPrivate> d; + RegExpConstructorPrivate d; }; RegExpConstructor* asRegExpConstructor(JSValue); @@ -122,20 +137,20 @@ namespace JSC { */ ALWAYS_INLINE void RegExpConstructor::performMatch(JSGlobalData& globalData, RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector) { - position = r->match(globalData, s, startOffset, &d->tempOvector()); + position = r->match(globalData, s, startOffset, &d.tempOvector()); if (ovector) - *ovector = d->tempOvector().data(); + *ovector = d.tempOvector().data(); if (position != -1) { - ASSERT(!d->tempOvector().isEmpty()); + ASSERT(!d.tempOvector().isEmpty()); - length = d->tempOvector()[1] - d->tempOvector()[0]; + length = d.tempOvector()[1] - d.tempOvector()[0]; - d->input = s; - d->lastInput = s; - d->changeLastOvector(); - d->lastNumSubPatterns = r->numSubpatterns(); + d.input = s; + d.lastInput = s; + d.changeLastOvector(); + d.lastNumSubPatterns = r->numSubpatterns(); } } diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h index a0a8a8e98..c34920d8d 100644 --- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h +++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h @@ -31,30 +31,29 @@ namespace JSC { public: typedef JSArray Base; - static RegExpMatchesArray* create(ExecState* exec, RegExpConstructorPrivate* ctorPrivate) + static RegExpMatchesArray* create(ExecState* exec, const RegExpConstructorPrivate& ctorPrivate) { RegExpMatchesArray* regExp = new (NotNull, allocateCell<RegExpMatchesArray>(*exec->heap())) RegExpMatchesArray(exec); regExp->finishCreation(exec->globalData(), ctorPrivate); return regExp; } - ~RegExpMatchesArray(); static void destroy(JSCell*); - static JS_EXPORTDATA const ClassInfo s_info; - + static const ClassInfo s_info; + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } - + protected: - void finishCreation(JSGlobalData&, RegExpConstructorPrivate* data); + void finishCreation(JSGlobalData&, const RegExpConstructorPrivate& data); private: static bool getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell); - if (thisObject->subclassData()) + if (!thisObject->m_didFillArrayInstance) thisObject->fillArrayInstance(exec); return JSArray::getOwnPropertySlot(thisObject, exec, propertyName, slot); } @@ -62,7 +61,7 @@ namespace JSC { static bool getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot) { RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell); - if (thisObject->subclassData()) + if (!thisObject->m_didFillArrayInstance) thisObject->fillArrayInstance(exec); return JSArray::getOwnPropertySlotByIndex(thisObject, exec, propertyName, slot); } @@ -70,7 +69,7 @@ namespace JSC { static bool getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) { RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object); - if (thisObject->subclassData()) + if (!thisObject->m_didFillArrayInstance) thisObject->fillArrayInstance(exec); return JSArray::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); } @@ -78,7 +77,7 @@ namespace JSC { static void put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue v, PutPropertySlot& slot) { RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell); - if (thisObject->subclassData()) + if (!thisObject->m_didFillArrayInstance) thisObject->fillArrayInstance(exec); JSArray::put(thisObject, exec, propertyName, v, slot); } @@ -86,7 +85,7 @@ namespace JSC { static void putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue v) { RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell); - if (thisObject->subclassData()) + if (!thisObject->m_didFillArrayInstance) thisObject->fillArrayInstance(exec); JSArray::putByIndex(thisObject, exec, propertyName, v); } @@ -94,7 +93,7 @@ namespace JSC { static bool deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName) { RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell); - if (thisObject->subclassData()) + if (!thisObject->m_didFillArrayInstance) thisObject->fillArrayInstance(exec); return JSArray::deleteProperty(thisObject, exec, propertyName); } @@ -102,7 +101,7 @@ namespace JSC { static bool deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName) { RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell); - if (thisObject->subclassData()) + if (!thisObject->m_didFillArrayInstance) thisObject->fillArrayInstance(exec); return JSArray::deletePropertyByIndex(thisObject, exec, propertyName); } @@ -110,12 +109,15 @@ namespace JSC { static void getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& arr, EnumerationMode mode = ExcludeDontEnumProperties) { RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object); - if (thisObject->subclassData()) + if (!thisObject->m_didFillArrayInstance) thisObject->fillArrayInstance(exec); JSArray::getOwnPropertyNames(thisObject, exec, arr, mode); } void fillArrayInstance(ExecState*); + + RegExpResult m_regExpResult; + bool m_didFillArrayInstance; }; } diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp index 4553f7ad0..4c192ff90 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.cpp +++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp @@ -231,7 +231,7 @@ JSValue RegExpObject::exec(ExecState* exec) bool RegExpObject::match(ExecState* exec) { RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); - UString input = exec->argument(0).toString(exec); + UString input = exec->argument(0).toString(exec)->value(exec); JSGlobalData* globalData = &exec->globalData(); if (!regExp()->global()) { int position; diff --git a/Source/JavaScriptCore/runtime/RegExpObject.h b/Source/JavaScriptCore/runtime/RegExpObject.h index 4e84d3831..081a7f111 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.h +++ b/Source/JavaScriptCore/runtime/RegExpObject.h @@ -75,8 +75,8 @@ namespace JSC { } protected: - RegExpObject(JSGlobalObject*, Structure*, RegExp*); - void finishCreation(JSGlobalObject*); + JS_EXPORT_PRIVATE RegExpObject(JSGlobalObject*, Structure*, RegExp*); + JS_EXPORT_PRIVATE void finishCreation(JSGlobalObject*); static void destroy(JSCell*); static const unsigned StructureFlags = OverridesVisitChildren | OverridesGetOwnPropertySlot | Base::StructureFlags; diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp index 6c79f9428..9074e97c3 100644 --- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -110,13 +110,13 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) return throwVMError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another.")); regExp = asRegExpObject(arg0)->regExp(); } else { - UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec); + UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); RegExpFlags flags = NoFlags; if (!arg1.isUndefined()) { - flags = regExpFlags(arg1.toString(exec)); + flags = regExpFlags(arg1.toString(exec)->value(exec)); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (flags == InvalidFlags) @@ -153,7 +153,7 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec) postfix[index++] = 'i'; if (thisObject->get(exec, exec->propertyNames().multiline).toBoolean(exec)) postfix[index] = 'm'; - UString source = thisObject->get(exec, exec->propertyNames().source).toString(exec); + UString source = thisObject->get(exec, exec->propertyNames().source).toString(exec)->value(exec); // If source is empty, use "/(?:)/" to avoid colliding with comment syntax return JSValue::encode(jsMakeNontrivialString(exec, "/", source.length() ? source : UString("(?:)"), postfix)); } diff --git a/Source/JavaScriptCore/runtime/SamplingCounter.h b/Source/JavaScriptCore/runtime/SamplingCounter.h index 664b0280e..329a5cfd3 100644 --- a/Source/JavaScriptCore/runtime/SamplingCounter.h +++ b/Source/JavaScriptCore/runtime/SamplingCounter.h @@ -46,7 +46,7 @@ public: m_counter += count; } - static void dump(); + JS_EXPORT_PRIVATE static void dump(); int64_t* addressOfCounter() { return &m_counter; } @@ -74,7 +74,7 @@ protected: AbstractSamplingCounter** m_referer; // Null object used to detect end of static chain. static AbstractSamplingCounter s_abstractSamplingCounterChainEnd; - static AbstractSamplingCounter* s_abstractSamplingCounterChain; + JS_EXPORTDATA static AbstractSamplingCounter* s_abstractSamplingCounterChain; static bool s_completed; }; diff --git a/Source/JavaScriptCore/runtime/SmallStrings.h b/Source/JavaScriptCore/runtime/SmallStrings.h index 9c6ed9a32..cd8e63095 100644 --- a/Source/JavaScriptCore/runtime/SmallStrings.h +++ b/Source/JavaScriptCore/runtime/SmallStrings.h @@ -60,7 +60,7 @@ namespace JSC { return m_singleCharacterStrings[character]; } - StringImpl* singleCharacterStringRep(unsigned char character); + JS_EXPORT_PRIVATE StringImpl* singleCharacterStringRep(unsigned char character); void finalizeSmallStrings(); void clear(); @@ -72,8 +72,8 @@ namespace JSC { private: static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1; - void createEmptyString(JSGlobalData*); - void createSingleCharacterString(JSGlobalData*, unsigned char); + JS_EXPORT_PRIVATE void createEmptyString(JSGlobalData*); + JS_EXPORT_PRIVATE void createSingleCharacterString(JSGlobalData*, unsigned char); JSString* m_emptyString; JSString* m_singleCharacterStrings[singleCharacterStringCount]; diff --git a/Source/JavaScriptCore/runtime/StringConstructor.cpp b/Source/JavaScriptCore/runtime/StringConstructor.cpp index d2f75a060..e03a87f03 100644 --- a/Source/JavaScriptCore/runtime/StringConstructor.cpp +++ b/Source/JavaScriptCore/runtime/StringConstructor.cpp @@ -95,10 +95,7 @@ static EncodedJSValue JSC_HOST_CALL constructWithStringConstructor(ExecState* ex if (!exec->argumentCount()) return JSValue::encode(StringObject::create(exec, globalObject->stringObjectStructure())); - JSString* string = exec->argument(0).isString() - ? asString(exec->argument(0)) - : jsString(exec, exec->argument(0).toString(exec)); - return JSValue::encode(StringObject::create(exec, globalObject->stringObjectStructure(), string)); + return JSValue::encode(StringObject::create(exec, globalObject->stringObjectStructure(), exec->argument(0).toString(exec))); } ConstructType StringConstructor::getConstructData(JSCell*, ConstructData& constructData) @@ -111,7 +108,7 @@ static EncodedJSValue JSC_HOST_CALL callStringConstructor(ExecState* exec) { if (!exec->argumentCount()) return JSValue::encode(jsEmptyString(exec)); - return JSValue::encode(jsString(exec, exec->argument(0).toString(exec))); + return JSValue::encode(exec->argument(0).toString(exec)); } CallType StringConstructor::getCallData(JSCell*, CallData& callData) diff --git a/Source/JavaScriptCore/runtime/StringObject.h b/Source/JavaScriptCore/runtime/StringObject.h index 528668691..248c71601 100644 --- a/Source/JavaScriptCore/runtime/StringObject.h +++ b/Source/JavaScriptCore/runtime/StringObject.h @@ -64,9 +64,9 @@ namespace JSC { } protected: - void finishCreation(JSGlobalData&, JSString*); + JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&, JSString*); static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSWrapperObject::StructureFlags; - StringObject(JSGlobalData&, Structure*); + JS_EXPORT_PRIVATE StringObject(JSGlobalData&, Structure*); }; StringObject* asStringObject(JSValue); diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp index 740916a69..63c00e27e 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -170,9 +170,10 @@ static inline JSString* jsStringWithReuse(ExecState* exec, JSValue originalValue return jsString(exec, string); } +template <typename CharType> static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacement, const UString& source, const int* ovector, RegExp* reg, size_t i) { - Vector<UChar> substitutedReplacement; + Vector<CharType> substitutedReplacement; int offset = 0; do { if (i + 1 == replacement.length()) @@ -182,7 +183,7 @@ static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacem if (ref == '$') { // "$$" -> "$" ++i; - substitutedReplacement.append(replacement.characters() + offset, i - offset); + substitutedReplacement.append(replacement.getCharacters<CharType>() + offset, i - offset); offset = i + 1; continue; } @@ -222,15 +223,15 @@ static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacem continue; if (i - offset) - substitutedReplacement.append(replacement.characters() + offset, i - offset); + substitutedReplacement.append(replacement.getCharacters<CharType>() + offset, i - offset); i += 1 + advance; offset = i + 1; if (backrefStart >= 0) - substitutedReplacement.append(source.characters() + backrefStart, backrefLength); + substitutedReplacement.append(source.getCharacters<CharType>() + backrefStart, backrefLength); } while ((i = replacement.find('$', i + 1)) != notFound); if (replacement.length() - offset) - substitutedReplacement.append(replacement.characters() + offset, replacement.length() - offset); + substitutedReplacement.append(replacement.getCharacters<CharType>() + offset, replacement.length() - offset); substitutedReplacement.shrinkToFit(); return UString::adopt(substitutedReplacement); @@ -239,8 +240,11 @@ static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacem static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg) { size_t i = replacement.find('$', 0); - if (UNLIKELY(i != notFound)) - return substituteBackreferencesSlow(replacement, source, ovector, reg, i); + if (UNLIKELY(i != notFound)) { + if (replacement.is8Bit() && source.is8Bit()) + return substituteBackreferencesSlow<LChar>(replacement, source, ovector, reg, i); + return substituteBackreferencesSlow<UChar>(replacement, source, ovector, reg, i); + } return replacement; } @@ -398,13 +402,54 @@ static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, J return jsString(exec, impl.release()); } +static NEVER_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSString* string, const UString& source, RegExp* regExp) +{ + int lastIndex = 0; + unsigned startPosition = 0; + + Vector<StringRange, 16> sourceRanges; + JSGlobalData* globalData = &exec->globalData(); + RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); + unsigned sourceLen = source.length(); + + while (true) { + int matchIndex; + int matchLen = 0; + int* ovector; + regExpConstructor->performMatch(*globalData, regExp, source, startPosition, matchIndex, matchLen, &ovector); + if (matchIndex < 0) + break; + + if (lastIndex < matchIndex) + sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex)); + + lastIndex = matchIndex + matchLen; + startPosition = lastIndex; + + // special case of empty match + if (!matchLen) { + startPosition++; + if (startPosition > sourceLen) + break; + } + } + + if (!lastIndex) + return JSValue::encode(string); + + if (static_cast<unsigned>(lastIndex) < sourceLen) + sourceRanges.append(StringRange(lastIndex, sourceLen - lastIndex)); + + return JSValue::encode(jsSpliceSubstrings(exec, string, source, sourceRanges.data(), sourceRanges.size())); +} + static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue) { UString replacementString; CallData callData; CallType callType = getCallData(replaceValue, callData); if (callType == CallTypeNone) - replacementString = replaceValue.toString(exec); + replacementString = replaceValue.toString(exec)->value(exec); const UString& source = string->value(exec); unsigned sourceLen = source.length(); @@ -413,45 +458,10 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS RegExp* regExp = asRegExpObject(searchValue)->regExp(); bool global = regExp->global(); - RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); - - // Optimization for substring removal (replace with empty). - if (global && callType == CallTypeNone && !replacementString.length()) { - int lastIndex = 0; - unsigned startPosition = 0; - - Vector<StringRange, 16> sourceRanges; - JSGlobalData* globalData = &exec->globalData(); - while (true) { - int matchIndex; - int matchLen = 0; - int* ovector; - regExpConstructor->performMatch(*globalData, regExp, source, startPosition, matchIndex, matchLen, &ovector); - if (matchIndex < 0) - break; - - if (lastIndex < matchIndex) - sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex)); - - lastIndex = matchIndex + matchLen; - startPosition = lastIndex; - - // special case of empty match - if (!matchLen) { - startPosition++; - if (startPosition > sourceLen) - break; - } - } - - if (!lastIndex) - return JSValue::encode(string); - - if (static_cast<unsigned>(lastIndex) < sourceLen) - sourceRanges.append(StringRange(lastIndex, sourceLen - lastIndex)); + if (global && callType == CallTypeNone && !replacementString.length()) + return removeUsingRegExpSearch(exec, string, source, regExp); - return JSValue::encode(jsSpliceSubstrings(exec, string, source, sourceRanges.data(), sourceRanges.size())); - } + RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int lastIndex = 0; unsigned startPosition = 0; @@ -496,10 +506,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS cachedCall.setThis(jsUndefined()); JSValue result = cachedCall.call(); - if (LIKELY(result.isString())) - replacements.append(asString(result)->value(exec)); - else - replacements.append(result.toString(cachedCall.newCallFrame(exec))); + replacements.append(result.toString(cachedCall.newCallFrame(exec))->value(exec)); if (exec->hadException()) break; @@ -541,10 +548,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS cachedCall.setThis(jsUndefined()); JSValue result = cachedCall.call(); - if (LIKELY(result.isString())) - replacements.append(asString(result)->value(exec)); - else - replacements.append(result.toString(cachedCall.newCallFrame(exec))); + replacements.append(result.toString(cachedCall.newCallFrame(exec))->value(exec)); if (exec->hadException()) break; @@ -588,7 +592,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS args.append(jsNumber(completeMatchStart)); args.append(string); - replacements.append(call(exec, replaceValue, callType, callData, jsUndefined(), args).toString(exec)); + replacements.append(call(exec, replaceValue, callType, callData, jsUndefined(), args).toString(exec)->value(exec)); if (exec->hadException()) break; } else { @@ -627,7 +631,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS static NEVER_INLINE EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue, JSValue replaceValue) { const UString& string = jsString->value(exec); - UString searchString = searchValue.toString(exec); + UString searchString = searchValue.toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -647,7 +651,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSS return JSValue::encode(jsUndefined()); } - UString replaceString = replaceValue.toString(exec); + UString replaceString = replaceValue.toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -659,12 +663,9 @@ static NEVER_INLINE EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSS EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.isString()) { - if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible - return throwVMTypeError(exec); - thisValue = jsString(exec, thisValue.toString(exec)); - } - JSString* string = asString(thisValue); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); + JSString* string = thisValue.toString(exec); JSValue searchValue = exec->argument(0); JSValue replaceValue = exec->argument(1); @@ -692,7 +693,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); unsigned len = s.length(); JSValue a0 = exec->argument(0); if (a0.isUInt32()) { @@ -712,7 +713,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); unsigned len = s.length(); JSValue a0 = exec->argument(0); if (a0.isUInt32()) { @@ -733,12 +734,9 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (thisValue.isString() && (exec->argumentCount() == 1)) { - JSValue v = exec->argument(0); - return JSValue::encode(v.isString() - ? jsString(exec, asString(thisValue), asString(v)) - : jsString(exec, asString(thisValue), jsString(&exec->globalData(), v.toString(exec)))); - } + if (thisValue.isString() && (exec->argumentCount() == 1)) + return JSValue::encode(jsString(exec, asString(thisValue), exec->argument(0).toString(exec))); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); return JSValue::encode(jsStringFromArguments(exec, thisValue)); @@ -749,12 +747,12 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); int len = s.length(); JSValue a0 = exec->argument(0); JSValue a1 = exec->argument(1); - UString u2 = a0.toString(exec); + UString u2 = a0.toString(exec)->value(exec); int pos; if (a1.isUndefined()) pos = 0; @@ -780,13 +778,13 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); int len = s.length(); JSValue a0 = exec->argument(0); JSValue a1 = exec->argument(1); - UString u2 = a0.toString(exec); + UString u2 = a0.toString(exec)->value(exec); double dpos = a1.toIntegerPreserveNaN(exec); if (dpos < 0) dpos = 0; @@ -804,7 +802,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); JSGlobalData* globalData = &exec->globalData(); JSValue a0 = exec->argument(0); @@ -819,7 +817,9 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) * replaced with the result of the expression new RegExp(regexp). * Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string. */ - reg = RegExp::create(exec->globalData(), a0.isUndefined() ? UString("") : a0.toString(exec), NoFlags); + reg = RegExp::create(exec->globalData(), a0.isUndefined() ? UString("") : a0.toString(exec)->value(exec), NoFlags); + if (!reg->isValid()) + return throwVMError(exec, createSyntaxError(exec, reg->errorMessage())); } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int pos; @@ -854,7 +854,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); JSGlobalData* globalData = &exec->globalData(); JSValue a0 = exec->argument(0); @@ -869,7 +869,9 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) * replaced with the result of the expression new RegExp(regexp). * Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string. */ - reg = RegExp::create(exec->globalData(), a0.isUndefined() ? UString("") : a0.toString(exec), NoFlags); + reg = RegExp::create(exec->globalData(), a0.isUndefined() ? UString("") : a0.toString(exec)->value(exec), NoFlags); + if (!reg->isValid()) + return throwVMError(exec, createSyntaxError(exec, reg->errorMessage())); } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int pos; @@ -883,7 +885,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); int len = s.length(); JSValue a0 = exec->argument(0); @@ -915,7 +917,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) // 2. Let S be the result of calling ToString, giving it the this value as its argument. // 6. Let s be the number of characters in S. - UString input = thisValue.toString(exec); + UString input = thisValue.toString(exec)->value(exec); // 3. Let A be a new array created as if by the expression new Array() // where Array is the standard built-in constructor with that name. @@ -1017,7 +1019,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) } } } else { - UString separator = separatorValue.toString(exec); + UString separator = separatorValue.toString(exec)->value(exec); // 9. If lim == 0, return A. if (!limit) @@ -1104,7 +1106,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec) // CheckObjectCoercible return throwVMTypeError(exec); } else { - uString = thisValue.toString(exec); + uString = thisValue.toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); len = uString.length(); @@ -1134,24 +1136,16 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - int len; - JSString* jsString = 0; - UString uString; - if (thisValue.isString()) { - jsString = static_cast<JSString*>(thisValue.asCell()); - len = jsString->length(); - } else if (thisValue.isUndefinedOrNull()) { - // CheckObjectCoercible + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - } else { - uString = thisValue.toString(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - len = uString.length(); - } + + JSString* jsString = thisValue.toString(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); JSValue a0 = exec->argument(0); JSValue a1 = exec->argument(1); + int len = jsString->length(); double start = a0.toNumber(exec); double end; @@ -1175,9 +1169,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec) } unsigned substringStart = static_cast<unsigned>(start); unsigned substringLength = static_cast<unsigned>(end) - substringStart; - if (jsString) - return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength)); - return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength)); + return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength)); } EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec) @@ -1185,16 +1177,16 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - JSString* sVal = thisValue.isString() ? asString(thisValue) : jsString(exec, thisValue.toString(exec)); + JSString* sVal = thisValue.toString(exec); const UString& s = sVal->value(exec); int sSize = s.length(); if (!sSize) return JSValue::encode(sVal); - StringImpl* ourImpl = s.impl(); + StringImpl* ourImpl = s.impl(); RefPtr<StringImpl> lower = ourImpl->lower(); - if (ourImpl == lower.get()) + if (ourImpl == lower) return JSValue::encode(sVal); return JSValue::encode(jsString(exec, UString(lower.release()))); } @@ -1204,39 +1196,18 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - JSString* sVal = thisValue.isString() ? asString(thisValue) : jsString(exec, thisValue.toString(exec)); + JSString* sVal = thisValue.toString(exec); const UString& s = sVal->value(exec); int sSize = s.length(); if (!sSize) return JSValue::encode(sVal); - const UChar* sData = s.characters(); - Vector<UChar> buffer(sSize); - - UChar ored = 0; - for (int i = 0; i < sSize; i++) { - UChar c = sData[i]; - ored |= c; - buffer[i] = toASCIIUpper(c); - } - if (!(ored & ~0x7f)) - return JSValue::encode(jsString(exec, UString::adopt(buffer))); - - bool error; - int length = Unicode::toUpper(buffer.data(), sSize, sData, sSize, &error); - if (error) { - buffer.resize(length); - length = Unicode::toUpper(buffer.data(), length, sData, sSize, &error); - if (error) - return JSValue::encode(sVal); - } - if (length == sSize) { - if (memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0) - return JSValue::encode(sVal); - } else - buffer.resize(length); - return JSValue::encode(jsString(exec, UString::adopt(buffer))); + StringImpl* sImpl = s.impl(); + RefPtr<StringImpl> upper = sImpl->upper(); + if (sImpl == upper) + return JSValue::encode(sVal); + return JSValue::encode(jsString(exec, UString(upper.release()))); } EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec) @@ -1247,10 +1218,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); - return JSValue::encode(jsNumber(localeCompare(s, a0.toString(exec)))); + return JSValue::encode(jsNumber(localeCompare(s, a0.toString(exec)->value(exec)))); } EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec) @@ -1258,7 +1229,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); return JSValue::encode(jsMakeNontrivialString(exec, "<big>", s, "</big>")); } @@ -1267,7 +1238,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); return JSValue::encode(jsMakeNontrivialString(exec, "<small>", s, "</small>")); } @@ -1276,7 +1247,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); return JSValue::encode(jsMakeNontrivialString(exec, "<blink>", s, "</blink>")); } @@ -1285,7 +1256,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); return JSValue::encode(jsMakeNontrivialString(exec, "<b>", s, "</b>")); } @@ -1294,7 +1265,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); return JSValue::encode(jsMakeNontrivialString(exec, "<tt>", s, "</tt>")); } @@ -1303,7 +1274,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); return JSValue::encode(jsMakeNontrivialString(exec, "<i>", s, "</i>")); } @@ -1312,7 +1283,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); return JSValue::encode(jsMakeNontrivialString(exec, "<strike>", s, "</strike>")); } @@ -1321,7 +1292,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); return JSValue::encode(jsMakeNontrivialString(exec, "<sub>", s, "</sub>")); } @@ -1330,7 +1301,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); return JSValue::encode(jsMakeNontrivialString(exec, "<sup>", s, "</sup>")); } @@ -1339,9 +1310,9 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); - return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", a0.toString(exec), "\">", s, "</font>")); + return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", a0.toString(exec)->value(exec), "\">", s, "</font>")); } EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec) @@ -1349,7 +1320,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); uint32_t smallInteger; @@ -1386,7 +1357,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec) return JSValue::encode(jsNontrivialString(exec, impl)); } - return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", a0.toString(exec), "\">", s, "</font>")); + return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", a0.toString(exec)->value(exec), "\">", s, "</font>")); } EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec) @@ -1394,9 +1365,9 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); - return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", a0.toString(exec), "\">", s, "</a>")); + return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", a0.toString(exec)->value(exec), "\">", s, "</a>")); } EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec) @@ -1404,9 +1375,9 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec) JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); - UString s = thisValue.toString(exec); + UString s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); - UString linkText = a0.toString(exec); + UString linkText = a0.toString(exec)->value(exec); unsigned linkTextSize = linkText.length(); unsigned stringSize = s.length(); @@ -1449,7 +1420,7 @@ static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKin { if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwTypeError(exec); - UString str = thisValue.toString(exec); + UString str = thisValue.toString(exec)->value(exec); unsigned left = 0; if (trimKind & TrimLeft) { while (left < str.length() && isTrimWhitespace(str[left])) diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index dda8c73e9..f387cf283 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -401,17 +401,26 @@ Structure* Structure::despecifyFunctionTransition(JSGlobalData& globalData, Stru return transition; } -Structure* Structure::getterSetterTransition(JSGlobalData& globalData, Structure* structure) +Structure* Structure::attributeChangeTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, unsigned attributes) { - Structure* transition = create(globalData, structure); + if (!structure->isUncacheableDictionary()) { + Structure* transition = create(globalData, structure); - // Don't set m_offset, as one can not transition to this. + // Don't set m_offset, as one can not transition to this. - structure->materializePropertyMapIfNecessary(globalData); - transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition); - transition->pin(); + structure->materializePropertyMapIfNecessary(globalData); + transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition); + transition->pin(); + + structure = transition; + } - return transition; + ASSERT(structure->m_propertyTable); + PropertyMapEntry* entry = structure->m_propertyTable->find(propertyName.impl()).first; + ASSERT(entry); + entry->attributes = attributes; + + return structure; } Structure* Structure::toDictionaryTransition(JSGlobalData& globalData, Structure* structure, DictionaryKind kind) diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index 70e968014..ced296856 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -84,12 +84,12 @@ namespace JSC { public: static void dumpStatistics(); - static Structure* addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset); - static Structure* addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset); + JS_EXPORT_PRIVATE static Structure* addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset); + JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset); static Structure* removePropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, size_t& offset); - static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype); - static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, const Identifier&); - static Structure* getterSetterTransition(JSGlobalData&, Structure*); + JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype); + JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, const Identifier&); + static Structure* attributeChangeTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes); static Structure* toCacheableDictionaryTransition(JSGlobalData&, Structure*); static Structure* toUncacheableDictionaryTransition(JSGlobalData&, Structure*); static Structure* sealTransition(JSGlobalData&, Structure*); @@ -106,7 +106,7 @@ namespace JSC { static void destroy(JSCell*); // These should be used with caution. - size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue); + JS_EXPORT_PRIVATE size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue); size_t removePropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName); void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); } @@ -136,7 +136,7 @@ namespace JSC { size_t get(JSGlobalData&, const Identifier& propertyName); size_t get(JSGlobalData&, const UString& name); - size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue); + JS_EXPORT_PRIVATE size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue); size_t get(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue) { ASSERT(!propertyName.isNull()); @@ -151,7 +151,7 @@ namespace JSC { bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; } - void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName); + JS_EXPORT_PRIVATE void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName); void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; } void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. @@ -196,7 +196,7 @@ namespace JSC { static JS_EXPORTDATA const ClassInfo s_info; private: - Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*); + JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*); Structure(JSGlobalData&); Structure(JSGlobalData&, const Structure*); @@ -226,7 +226,7 @@ namespace JSC { PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner); PassOwnPtr<PropertyTable> copyPropertyTableForPinning(JSGlobalData&, Structure* owner); - void materializePropertyMap(JSGlobalData&); + JS_EXPORT_PRIVATE void materializePropertyMap(JSGlobalData&); void materializePropertyMapIfNecessary(JSGlobalData& globalData) { ASSERT(structure()->classInfo() == &s_info); diff --git a/Source/JavaScriptCore/runtime/TimeoutChecker.h b/Source/JavaScriptCore/runtime/TimeoutChecker.h index 5925641f8..89d6158cc 100644 --- a/Source/JavaScriptCore/runtime/TimeoutChecker.h +++ b/Source/JavaScriptCore/runtime/TimeoutChecker.h @@ -57,9 +57,9 @@ namespace JSC { --m_startCount; } - void reset(); + JS_EXPORT_PRIVATE void reset(); - bool didTimeOut(ExecState*); + JS_EXPORT_PRIVATE bool didTimeOut(ExecState*); private: unsigned m_timeoutInterval; diff --git a/Source/JavaScriptCore/runtime/UString.h b/Source/JavaScriptCore/runtime/UString.h index c05ae5081..668eb0489 100644 --- a/Source/JavaScriptCore/runtime/UString.h +++ b/Source/JavaScriptCore/runtime/UString.h @@ -33,18 +33,18 @@ public: UString() { } // Construct a string with UTF-16 data. - UString(const UChar* characters, unsigned length); + JS_EXPORT_PRIVATE UString(const UChar* characters, unsigned length); // Construct a string with UTF-16 data, from a null-terminated source. - UString(const UChar*); + JS_EXPORT_PRIVATE UString(const UChar*); // Construct a string with latin1 data. UString(const LChar* characters, unsigned length); - UString(const char* characters, unsigned length); + JS_EXPORT_PRIVATE UString(const char* characters, unsigned length); // Construct a string with latin1 data, from a null-terminated source. UString(const LChar* characters); - UString(const char* characters); + JS_EXPORT_PRIVATE UString(const char* characters); // Construct a string referencing an existing StringImpl. UString(StringImpl* impl) : m_impl(impl) { } @@ -99,9 +99,9 @@ public: bool is8Bit() const { return m_impl->is8Bit(); } - CString ascii() const; + JS_EXPORT_PRIVATE CString ascii() const; CString latin1() const; - CString utf8(bool strict = false) const; + JS_EXPORT_PRIVATE CString utf8(bool strict = false) const; UChar operator[](unsigned index) const { @@ -112,11 +112,11 @@ public: return m_impl->characters16()[index]; } - static UString number(int); - static UString number(unsigned); - static UString number(long); + JS_EXPORT_PRIVATE static UString number(int); + JS_EXPORT_PRIVATE static UString number(unsigned); + JS_EXPORT_PRIVATE static UString number(long); static UString number(long long); - static UString number(double); + JS_EXPORT_PRIVATE static UString number(double); // Find a single character or string, also with match function & latin1 forms. size_t find(UChar c, unsigned start = 0) const @@ -132,25 +132,17 @@ public: size_t reverseFind(const UString& str, unsigned start = UINT_MAX) const { return m_impl ? m_impl->reverseFind(str.impl(), start) : notFound; } - UString substringSharingImpl(unsigned pos, unsigned len = UINT_MAX) const; + JS_EXPORT_PRIVATE UString substringSharingImpl(unsigned pos, unsigned len = UINT_MAX) const; private: RefPtr<StringImpl> m_impl; }; template<> -inline const LChar* UString::getCharacters<LChar>() const -{ - ASSERT(is8Bit()); - return characters8(); -} +inline const LChar* UString::getCharacters<LChar>() const { return characters8(); } template<> -inline const UChar* UString::getCharacters<UChar>() const -{ - ASSERT(!is8Bit()); - return characters16(); -} +inline const UChar* UString::getCharacters<UChar>() const { return characters(); } NEVER_INLINE bool equalSlowCase(const UString& s1, const UString& s2); @@ -189,10 +181,10 @@ inline bool operator!=(const UString& s1, const UString& s2) return !JSC::operator==(s1, s2); } -bool operator<(const UString& s1, const UString& s2); -bool operator>(const UString& s1, const UString& s2); +JS_EXPORT_PRIVATE bool operator<(const UString& s1, const UString& s2); +JS_EXPORT_PRIVATE bool operator>(const UString& s1, const UString& s2); -bool operator==(const UString& s1, const char* s2); +JS_EXPORT_PRIVATE bool operator==(const UString& s1, const char* s2); inline bool operator!=(const UString& s1, const char* s2) { diff --git a/Source/JavaScriptCore/runtime/WriteBarrier.h b/Source/JavaScriptCore/runtime/WriteBarrier.h index 525fc0926..a7bd7a100 100644 --- a/Source/JavaScriptCore/runtime/WriteBarrier.h +++ b/Source/JavaScriptCore/runtime/WriteBarrier.h @@ -40,8 +40,8 @@ class JSGlobalObject; template<class T> class WriteBarrierBase; template<> class WriteBarrierBase<JSValue>; -void slowValidateCell(JSCell*); -void slowValidateCell(JSGlobalObject*); +JS_EXPORT_PRIVATE void slowValidateCell(JSCell*); +JS_EXPORT_PRIVATE void slowValidateCell(JSGlobalObject*); #if ENABLE(GC_VALIDATION) template<class T> inline void validateCell(T cell) diff --git a/Source/JavaScriptCore/tools/CodeProfile.cpp b/Source/JavaScriptCore/tools/CodeProfile.cpp new file mode 100644 index 000000000..7794f58d3 --- /dev/null +++ b/Source/JavaScriptCore/tools/CodeProfile.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CodeProfile.h" + +#include "CodeBlock.h" +#include "CodeProfiling.h" +#include "LinkBuffer.h" +#include "ProfileTreeNode.h" +#include "Vector.h" +#include <wtf/text/WTFString.h> + +#if PLATFORM(MAC) +#include <cxxabi.h> +#include <dlfcn.h> +#include <execinfo.h> +#endif + +namespace JSC { + +// Map from CodeType enum to a corresponding name. +const char* CodeProfile::s_codeTypeNames[CodeProfile::NumberOfCodeTypes] = { + "[[EngineCode]]", + "[[GlobalThunk]]", + "[[RegExpCode]]", + "[[DFGJIT]]", + "[[BaselineOnly]]", + "[[BaselineProfile]]", + "[[BaselineOSR]]", + "[[EngineFrame]]" +}; + +// Helper function, find the symbol name for a pc in JSC. +static const char* symbolName(void* address) +{ +#if PLATFORM(MAC) + Dl_info info; + if (!dladdr(address, &info) || !info.dli_sname) + return "<unknown>"; + + const char* mangledName = info.dli_sname; + const char* cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0); + return cxaDemangled ? cxaDemangled : mangledName; +#else + UNUSED_PARAM(address); + return "<unknown>"; +#endif +} + +// Helper function, truncate traces to prune the output & make very verbose mode a little more readable. +static bool truncateTrace(const char* symbolName) +{ + return !strcmp(symbolName, "JSC::BytecodeGenerator::generate()") + || !strcmp(symbolName, "JSC::Parser<JSC::Lexer<unsigned char> >::parseInner()") + || !strcmp(symbolName, "WTF::fastMalloc(unsigned long)") + || !strcmp(symbolName, "WTF::calculateUTCOffset()") + || !strcmp(symbolName, "JSC::DFG::ByteCodeParser::parseCodeBlock()"); + +} + +// Each trace consists of a sequence of zero or more 'EngineFrame' entries, +// followed by a sample in JIT code, or one or more 'EngineFrame' entries, +// followed by a 'EngineCode' terminator. +void CodeProfile::sample(void* pc, void** framePointer) +{ + // Disallow traces containing only a 'EngineCode' terminator, without any 'EngineFrame' frames. + if (!framePointer) + return; + + while (framePointer) { + CodeType type; + +#if ENABLE(JIT) + // Determine if this sample fell in JIT code, and if so, from which JIT & why. + void* ownerUID = CodeProfiling::getOwnerUIDForPC(pc); + + if (!ownerUID) + type = EngineFrame; + else if (ownerUID == GLOBAL_THUNK_ID) + type = GlobalThunk; + else if (ownerUID == REGEXP_CODE_ID) + type = RegExpCode; + else { + CodeBlock* codeBlock = static_cast<CodeBlock*>(ownerUID); + if (codeBlock->getJITType() == JITCode::DFGJIT) + type = DFGJIT; + else if (codeBlock->canCompileWithDFGState() == CodeBlock::CompileWithDFGFalse) + type = BaselineOnly; + else if (codeBlock->replacement()) + type = BaselineOSR; + else + type = BaselineProfile; + } +#else + type = EngineFrame; +#endif + + // A sample in JIT code terminates the trace. + m_samples.append(CodeRecord(pc, type)); + if (type != EngineFrame) + return; + + // Walk up the stack. +#if PLATFORM(MAC) && CPU(X86_64) + pc = framePointer[1]; + framePointer = reinterpret_cast<void**>(*framePointer); +#else + // This platform is not yet supported! + ASSERT_NOT_REACHED(); +#endif + } + + // If we get here, we walked the entire stack without finding any frames of JIT code. + m_samples.append(CodeRecord(0, EngineCode)); +} + +void CodeProfile::report() +{ + fprintf(stdout, "<CodeProfiling %s:%d>\n", m_file.data(), m_lineNo); + + // How many frames of C-code to print - 0, if not verbose, 1 if verbose, up to 1024 if very verbose. + unsigned recursionLimit = CodeProfiling::beVeryVerbose() ? 1024 : CodeProfiling::beVerbose(); + + ProfileTreeNode profile; + + // Walk through the sample buffer. + size_t trace = 0; + while (trace < m_samples.size()) { + + // All traces are zero or more 'EngineFrame's, followed by a non-'EngineFrame'. + // Scan to find the last sample in the trace. + size_t lastInTrace = trace; + while (m_samples[lastInTrace].type == EngineFrame) + ++lastInTrace; + + // We use the last sample type to look up a name (used as a bucket in the profiler). + ProfileTreeNode* callbacks = profile.sampleChild(s_codeTypeNames[m_samples[lastInTrace].type]); + + // If there are any samples in C-code, add up to recursionLimit of them into the profile tree. + size_t lastEngineFrame = lastInTrace; + for (unsigned count = 0; lastEngineFrame > trace && count < recursionLimit; ++count) { + --lastEngineFrame; + ASSERT(m_samples[lastEngineFrame].type == EngineFrame); + const char* name = symbolName(m_samples[lastEngineFrame].pc); + callbacks = callbacks->sampleChild(name); + if (truncateTrace(name)) + break; + } + + // Move on to the next trace. + trace = lastInTrace + 1; + ASSERT(trace <= m_samples.size()); + } + + // Output the profile tree. + fprintf(stdout, "Total samples: %lld\n", static_cast<long long>(profile.childCount())); + profile.dump(); + + for (size_t i = 0 ; i < m_children.size(); ++i) + m_children[i]->report(); + + fprintf(stdout, "</CodeProfiling %s:%d>\n", m_file.data(), m_lineNo); +} + +} diff --git a/Source/JavaScriptCore/tools/CodeProfile.h b/Source/JavaScriptCore/tools/CodeProfile.h new file mode 100644 index 000000000..ea360bcbc --- /dev/null +++ b/Source/JavaScriptCore/tools/CodeProfile.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 CodeProfile_h +#define CodeProfile_h + +#include "SourceCode.h" +#include "TieredMMapArray.h" +#include <wtf/text/CString.h> + +namespace JSC { + +class CodeProfile { +public: + CodeProfile(const SourceCode& source, CodeProfile* parent) + : m_file(source.provider()->url().utf8()) + , m_lineNo(source.firstLine()) + , m_parent(parent) + { + if (parent) + parent->addChild(this); + } + + void sample(void* pc, void** framePointer); + void report(); + + CodeProfile* parent() + { + return m_parent; + } + + void addChild(CodeProfile* child) + { + m_children.append(adoptPtr(child)); + } + +private: + enum CodeType { + EngineCode, + GlobalThunk, + RegExpCode, + DFGJIT, + BaselineOnly, + BaselineProfile, + BaselineOSR, + EngineFrame, + NumberOfCodeTypes + }; + struct CodeRecord { + CodeRecord(void* pc, CodeType type) + : pc(pc) + , type(type) + { + } + void* pc; + CodeType type; + }; + + CString m_file; + unsigned m_lineNo; + CodeProfile* m_parent; + Vector< OwnPtr<CodeProfile> > m_children; + TieredMMapArray<CodeRecord> m_samples; + + static const char* s_codeTypeNames[NumberOfCodeTypes]; +}; + +} + +#endif // CodeProfile_h + diff --git a/Source/JavaScriptCore/tools/CodeProfiling.cpp b/Source/JavaScriptCore/tools/CodeProfiling.cpp new file mode 100644 index 000000000..f236484c9 --- /dev/null +++ b/Source/JavaScriptCore/tools/CodeProfiling.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CodeProfiling.h" + +#include "CodeProfile.h" +#include "MetaAllocator.h" +#include "signal.h" + +namespace JSC { + +volatile CodeProfile* CodeProfiling::s_profileStack = 0; +CodeProfiling::Mode CodeProfiling::s_mode = CodeProfiling::Disabled; +WTF::MetaAllocatorTracker* CodeProfiling::s_tracker = 0; + +#if COMPILER(CLANG) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-noreturn" +#endif + +#if PLATFORM(MAC) && CPU(X86_64) +// Helper function to start & stop the timer. +// Presently we're using the wall-clock timer, since this seems to give the best results. +static void setProfileTimer(unsigned usec) +{ + itimerval timer; + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = usec; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = usec; + setitimer(ITIMER_REAL, &timer, 0); +} +#endif + +#if COMPILER(CLANG) +#pragma clang diagnostic pop +#endif + +#if PLATFORM(MAC) && CPU(X86_64) +static void profilingTimer(int, siginfo_t*, void* uap) +{ + mcontext_t context = static_cast<ucontext_t*>(uap)->uc_mcontext; + CodeProfiling::sample(reinterpret_cast<void*>(context->__ss.__rip), + reinterpret_cast<void**>(context->__ss.__rbp)); +} +#endif + +// Callback triggered when the timer is fired. +void CodeProfiling::sample(void* pc, void** framePointer) +{ + CodeProfile* profileStack = const_cast<CodeProfile*>(s_profileStack); + if (profileStack) + profileStack->sample(pc, framePointer); +} + +void CodeProfiling::notifyAllocator(WTF::MetaAllocator* allocator) +{ + // Check for JSC_CODE_PROFILING. + const char* codeProfilingMode = getenv("JSC_CODE_PROFILING"); + if (!codeProfilingMode) + return; + + // Check for a valid mode, currently "1", "2", or "3". + if (!codeProfilingMode[0] || codeProfilingMode[1]) + return; + switch (*codeProfilingMode) { + case '1': + s_mode = Enabled; + break; + case '2': + s_mode = Verbose; + break; + case '3': + s_mode = VeryVerbose; + break; + default: + return; + } + + ASSERT(enabled()); + ASSERT(!s_tracker); + s_tracker = new WTF::MetaAllocatorTracker(); + allocator->trackAllocations(s_tracker); +} + +void* CodeProfiling::getOwnerUIDForPC(void* address) +{ + if (!s_tracker) + return 0; + WTF::MetaAllocatorHandle* handle = s_tracker->find(address); + if (!handle) + return 0; + return handle->ownerUID(); +} + +void CodeProfiling::begin(const SourceCode& source) +{ + // Push a new CodeProfile onto the stack for each script encountered. + CodeProfile* profileStack = const_cast<CodeProfile*>(s_profileStack); + bool alreadyProfiling = profileStack; + s_profileStack = profileStack = new CodeProfile(source, profileStack); + + // Is the profiler already running - if so, the timer will already be set up. + if (alreadyProfiling) + return; + +#if PLATFORM(MAC) && CPU(X86_64) + // Regsiter a signal handler & itimer. + struct sigaction action; + action.sa_sigaction = reinterpret_cast<void (*)(int, struct __siginfo *, void *)>(profilingTimer); + sigfillset(&action.sa_mask); + action.sa_flags = SA_SIGINFO; + sigaction(SIGALRM, &action, 0); + setProfileTimer(100); +#endif +} + +void CodeProfiling::end() +{ + // Pop the current profiler off the stack. + CodeProfile* current = const_cast<CodeProfile*>(s_profileStack); + ASSERT(current); + s_profileStack = current->parent(); + + // Is this the outermost script being profiled? - if not, just return. + // We perform all output of profiles recursively from the outermost script, + // to minimize profiling overhead from skewing results. + if (s_profileStack) + return; + +#if PLATFORM(MAC) && CPU(X86_64) + // Stop profiling + setProfileTimer(0); +#endif + + current->report(); + delete current; +} + +} diff --git a/Source/JavaScriptCore/tools/CodeProfiling.h b/Source/JavaScriptCore/tools/CodeProfiling.h new file mode 100644 index 000000000..9b0f5daa3 --- /dev/null +++ b/Source/JavaScriptCore/tools/CodeProfiling.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 CodeProfiling_h +#define CodeProfiling_h + +namespace WTF { + +class MetaAllocator; +class MetaAllocatorTracker; + +} + +namespace JSC { + +class CodeProfile; +class SourceCode; + +class CodeProfiling { + enum Mode { + Disabled, + Enabled, + Verbose, + VeryVerbose + }; + +public: + CodeProfiling(const SourceCode& source) + : m_active(enabled()) + { + if (m_active) + begin(source); + } + + ~CodeProfiling() + { + if (m_active) + end(); + } + + static bool enabled() { return s_mode != Disabled; } + static bool beVerbose() { return s_mode >= Verbose; } + static bool beVeryVerbose() { return s_mode >= VeryVerbose; } + + static void notifyAllocator(WTF::MetaAllocator*); + static void* getOwnerUIDForPC(void*); + static void sample(void* pc, void** framePointer); + +private: + void begin(const SourceCode&); + void end(); + + bool m_active; + + static Mode s_mode; + static WTF::MetaAllocatorTracker* s_tracker; + static volatile CodeProfile* s_profileStack; +}; + +} + +#endif // CodeProfiling_h + diff --git a/Source/JavaScriptCore/tools/ProfileTreeNode.h b/Source/JavaScriptCore/tools/ProfileTreeNode.h new file mode 100644 index 000000000..6c5fdc185 --- /dev/null +++ b/Source/JavaScriptCore/tools/ProfileTreeNode.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 ProfileTreeNode_h +#define ProfileTreeNode_h + +namespace JSC { + +class ProfileTreeNode { + typedef HashMap<String, ProfileTreeNode> Map; + typedef std::pair<String, ProfileTreeNode> MapEntry; + +public: + ProfileTreeNode() + : m_count(0) + , m_children(0) + { + } + + ~ProfileTreeNode() + { + delete m_children; + } + + ProfileTreeNode* sampleChild(const char* name) + { + if (!m_children) + m_children = new Map(); + + ProfileTreeNode newEntry; + pair<Map::iterator, bool> result = m_children->add(String(name), newEntry); + ProfileTreeNode* childInMap = &result.first->second; + ++childInMap->m_count; + return childInMap; + } + + void dump() + { + dumpInternal(0); + } + + uint64_t count() + { + return m_count; + } + + uint64_t childCount() + { + if (!m_children) + return 0; + uint64_t childCount = 0; + for (Map::iterator it = m_children->begin(); it != m_children->end(); ++it) + childCount += it->second.count(); + return childCount; + } + +private: + void dumpInternal(unsigned indent) + { + if (!m_children) + return; + + // Copy pointers to all children into a vector, and sort the vector by sample count. + Vector<MapEntry*> entries; + for (Map::iterator it = m_children->begin(); it != m_children->end(); ++it) + entries.append(&*it); + qsort(entries.begin(), entries.size(), sizeof(MapEntry*), compareEntries); + + // Iterate over the children in sample-frequency order. + for (size_t e = 0; e < entries.size(); ++e) { + MapEntry* entry = entries[e]; + + // Print the number of samples, the name of this node, and the number of samples that are stack-top + // in this node (samples directly within this node, excluding samples in children. + for (unsigned i = 0; i < indent; ++i) + fprintf(stdout, " "); + fprintf(stdout, "% 8lld: %s (%lld stack top)\n", + static_cast<long long>(entry->second.count()), + entry->first.utf8().data(), + static_cast<long long>(entry->second.count() - entry->second.childCount())); + + // Recursively dump the child nodes. + entry->second.dumpInternal(indent + 1); + } + } + + static int compareEntries(const void* a, const void* b) + { + uint64_t da = (*static_cast<MapEntry* const *>(a))->second.count(); + uint64_t db = (*static_cast<MapEntry* const *>(b))->second.count(); + return (da < db) - (da > db); + } + + uint64_t m_count; + Map* m_children; +}; + +} + +#endif // ProfileTreeNode_h + diff --git a/Source/JavaScriptCore/tools/TieredMMapArray.h b/Source/JavaScriptCore/tools/TieredMMapArray.h new file mode 100644 index 000000000..fa6e5ae1f --- /dev/null +++ b/Source/JavaScriptCore/tools/TieredMMapArray.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 TieredMMapArray_h +#define TieredMMapArray_h + +#include "OSAllocator.h" + +namespace JSC { + +// This class implements a simple array class that can be grown by appending items to the end. +// This class is implemented purely in terms of system allocations, with no malloc/free, so that +// it can safely be used from a secondary thread whilst the main thrad is paused (potentially +// holding the fast malloc heap lock). +template<typename T> +class TieredMMapArray { + static const size_t entriesPerBlock = 4096; + +public: + TieredMMapArray() + : m_directoryCount(4096) + , m_directory(static_cast<T**>(OSAllocator::reserveAndCommit(m_directoryCount * sizeof(T*)))) + , m_size(0) + { + for (size_t block = 0; block < m_directoryCount; ++block) + m_directory[block] = 0; + } + + ~TieredMMapArray() + { + size_t usedCount = (m_size + (entriesPerBlock - 1)) / entriesPerBlock; + ASSERT(usedCount == m_directoryCount || !m_directory[usedCount]); + + for (size_t block = 0; block < usedCount; ++block) { + ASSERT(m_directory[block]); + OSAllocator::decommitAndRelease(m_directory[block], entriesPerBlock * sizeof(T)); + } + + OSAllocator::decommitAndRelease(m_directory, m_directoryCount * sizeof(T*)); + } + + T& operator[](size_t index) + { + ASSERT(index < m_size); + size_t block = index / entriesPerBlock; + size_t offset = index % entriesPerBlock; + + ASSERT(m_directory[block]); + return m_directory[block][offset]; + } + + void append(const T& value) + { + // Check if the array is completely full, if so create more capacity in the directory. + if (m_size == m_directoryCount * entriesPerBlock) { + // Reallocate the directory. + size_t oldDirectorySize = m_directoryCount * sizeof(T*); + size_t newDirectorySize = oldDirectorySize * 2; + if (newDirectorySize < oldDirectorySize) + CRASH(); + m_directory = OSAllocator::reallocateCommitted(m_directory, oldDirectorySize, newDirectorySize); + + // + size_t newDirectoryCount = m_directoryCount * 2; + for (size_t block = m_directoryCount; block < newDirectoryCount; ++block) + m_directory[block] = 0; + m_directoryCount = newDirectoryCount; + } + + size_t index = m_size; + size_t block = index / entriesPerBlock; + size_t offset = index % entriesPerBlock; + + if (!offset) { + ASSERT(!m_directory[block]); + m_directory[block] = static_cast<T*>(OSAllocator::reserveAndCommit(entriesPerBlock * sizeof(T))); + } + + ASSERT(m_directory[block]); + ++m_size; + m_directory[block][offset] = value; + } + + size_t size() const { return m_size; } + +private: + size_t m_directoryCount; + T** m_directory; + size_t m_size; +}; + +} + +#endif // TieredMMapArray_h + diff --git a/Source/JavaScriptCore/wtf/ASCIICType.h b/Source/JavaScriptCore/wtf/ASCIICType.h index 17006ae2d..18e108e1b 100644 --- a/Source/JavaScriptCore/wtf/ASCIICType.h +++ b/Source/JavaScriptCore/wtf/ASCIICType.h @@ -111,6 +111,16 @@ template<typename CharType> inline CharType toASCIILower(CharType c) return c | ((c >= 'A' && c <= 'Z') << 5); } +template<typename CharType> inline CharType toASCIILowerUnchecked(CharType character) +{ + // This function can be used for comparing any input character + // to a lowercase English character. The isASCIIAlphaCaselessEqual + // below should be used for regular comparison of ASCII alpha + // characters, but switch statements in CSS tokenizer require + // direct use of this function. + return character | 0x20; +} + template<typename CharType> inline CharType toASCIIUpper(CharType c) { return c & ~((c >= 'a' && c <= 'z') << 5); @@ -140,6 +150,14 @@ inline char upperNibbleToASCIIHexDigit(char c) return nibble < 10 ? '0' + nibble : 'A' + nibble - 10; } +template<typename CharType> inline bool isASCIIAlphaCaselessEqual(CharType cssCharacter, char character) +{ + // This function compares a (preferrably) constant ASCII + // lowercase letter to any input character. + ASSERT(character >= 'a' && character <= 'z'); + return LIKELY(toASCIILowerUnchecked(cssCharacter) == character); +} + } using WTF::isASCII; @@ -154,8 +172,10 @@ using WTF::isASCIISpace; using WTF::isASCIIUpper; using WTF::toASCIIHexValue; using WTF::toASCIILower; +using WTF::toASCIILowerUnchecked; using WTF::toASCIIUpper; using WTF::lowerNibbleToASCIIHexDigit; using WTF::upperNibbleToASCIIHexDigit; +using WTF::isASCIIAlphaCaselessEqual; #endif diff --git a/Source/JavaScriptCore/wtf/Alignment.h b/Source/JavaScriptCore/wtf/Alignment.h index d42b307ed..9b443efc6 100644 --- a/Source/JavaScriptCore/wtf/Alignment.h +++ b/Source/JavaScriptCore/wtf/Alignment.h @@ -26,7 +26,7 @@ namespace WTF { -#if COMPILER(GCC) || COMPILER(MINGW) || COMPILER(RVCT) || COMPILER(GCCE) +#if COMPILER(GCC) || COMPILER(MINGW) || COMPILER(RVCT) || COMPILER(GCCE) || (COMPILER(SUNCC) && __SUNPRO_CC > 0x590) #define WTF_ALIGN_OF(type) __alignof__(type) #define WTF_ALIGNED(variable_type, variable, n) variable_type variable __attribute__((__aligned__(n))) #elif COMPILER(MSVC) diff --git a/Source/JavaScriptCore/wtf/ArrayBufferView.h b/Source/JavaScriptCore/wtf/ArrayBufferView.h index ccb7fd348..24ce25a5e 100644 --- a/Source/JavaScriptCore/wtf/ArrayBufferView.h +++ b/Source/JavaScriptCore/wtf/ArrayBufferView.h @@ -40,6 +40,7 @@ class ArrayBufferView : public RefCounted<ArrayBufferView> { public: virtual bool isByteArray() const { return false; } virtual bool isUnsignedByteArray() const { return false; } + virtual bool isUnsignedByteClampedArray() const { return false; } virtual bool isShortArray() const { return false; } virtual bool isUnsignedShortArray() const { return false; } virtual bool isIntArray() const { return false; } @@ -65,10 +66,10 @@ class ArrayBufferView : public RefCounted<ArrayBufferView> { virtual unsigned byteLength() const = 0; - virtual ~ArrayBufferView(); + WTF_EXPORT_PRIVATE virtual ~ArrayBufferView(); protected: - ArrayBufferView(PassRefPtr<ArrayBuffer>, unsigned byteOffset); + WTF_EXPORT_PRIVATE ArrayBufferView(PassRefPtr<ArrayBuffer>, unsigned byteOffset); inline bool setImpl(ArrayBufferView*, unsigned byteOffset); @@ -118,7 +119,7 @@ class ArrayBufferView : public RefCounted<ArrayBufferView> { *numElements = std::min(remainingElements, *numElements); } - virtual void neuter(); + WTF_EXPORT_PRIVATE virtual void neuter(); // This is the address of the ArrayBuffer's storage, plus the byte offset. void* m_baseAddress; diff --git a/Source/JavaScriptCore/wtf/Assertions.cpp b/Source/JavaScriptCore/wtf/Assertions.cpp index 3da67effe..80afcf414 100644 --- a/Source/JavaScriptCore/wtf/Assertions.cpp +++ b/Source/JavaScriptCore/wtf/Assertions.cpp @@ -272,6 +272,16 @@ void WTFGetBacktrace(void** stack, int* size) #endif } +#if OS(DARWIN) || OS(LINUX) +# if PLATFORM(QT) || PLATFORM(GTK) +# if defined(__GLIBC__) && !defined(__UCLIBC__) +# define WTF_USE_BACKTRACE_SYMBOLS 1 +# endif +# else +# define WTF_USE_DLADDR 1 +# endif +#endif + void WTFReportBacktrace() { static const int framesToShow = 31; @@ -281,11 +291,18 @@ void WTFReportBacktrace() WTFGetBacktrace(samples, &frames); +#if USE(BACKTRACE_SYMBOLS) + char** symbols = backtrace_symbols(samples, frames); + if (!symbols) + return; +#endif + for (int i = framesToSkip; i < frames; ++i) { const char* mangledName = 0; char* cxaDemangled = 0; - -#if !PLATFORM(GTK) && !PLATFORM(QT) && (OS(DARWIN) || OS(LINUX)) +#if USE(BACKTRACE_SYMBOLS) + mangledName = symbols[i]; +#elif USE(DLADDR) Dl_info info; if (dladdr(samples[i], &info) && info.dli_sname) mangledName = info.dli_sname; @@ -299,6 +316,26 @@ void WTFReportBacktrace() printf_stderr_common("%-3d %p\n", frameNumber, samples[i]); free(cxaDemangled); } + +#if USE(BACKTRACE_SYMBOLS) + free(symbols); +#endif +} + +#undef WTF_USE_BACKTRACE_SYMBOLS +#undef WTF_USE_DLADDR + +static WTFCrashHookFunction globalHook = 0; + +void WTFSetCrashHook(WTFCrashHookFunction function) +{ + globalHook = function; +} + +void WTFInvokeCrashHook() +{ + if (globalHook) + globalHook(); } void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...) diff --git a/Source/JavaScriptCore/wtf/Assertions.h b/Source/JavaScriptCore/wtf/Assertions.h index 2b3d794a4..42dc0bd35 100644 --- a/Source/JavaScriptCore/wtf/Assertions.h +++ b/Source/JavaScriptCore/wtf/Assertions.h @@ -147,6 +147,10 @@ WTF_EXPORT_PRIVATE void WTFLogVerbose(const char* file, int line, const char* fu WTF_EXPORT_PRIVATE void WTFGetBacktrace(void** stack, int* size); WTF_EXPORT_PRIVATE void WTFReportBacktrace(); +typedef void (*WTFCrashHookFunction)(); +WTF_EXPORT_PRIVATE void WTFSetCrashHook(WTFCrashHookFunction); +WTF_EXPORT_PRIVATE void WTFInvokeCrashHook(); + #ifdef __cplusplus } #endif @@ -163,12 +167,14 @@ WTF_EXPORT_PRIVATE void WTFReportBacktrace(); #if COMPILER(CLANG) #define CRASH() do { \ WTFReportBacktrace(); \ + WTFInvokeCrashHook(); \ *(int *)(uintptr_t)0xbbadbeef = 0; \ __builtin_trap(); \ } while (false) #else #define CRASH() do { \ WTFReportBacktrace(); \ + WTFInvokeCrashHook(); \ *(int *)(uintptr_t)0xbbadbeef = 0; \ ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \ } while (false) diff --git a/Source/JavaScriptCore/wtf/ByteArray.h b/Source/JavaScriptCore/wtf/ByteArray.h index 6964a33df..f68d032fd 100644 --- a/Source/JavaScriptCore/wtf/ByteArray.h +++ b/Source/JavaScriptCore/wtf/ByteArray.h @@ -83,7 +83,7 @@ namespace WTF { } } - static PassRefPtr<ByteArray> create(size_t size); + WTF_EXPORT_PRIVATE static PassRefPtr<ByteArray> create(size_t size); static size_t offsetOfSize() { return OBJECT_OFFSETOF(ByteArray, m_size); } static size_t offsetOfData() { return OBJECT_OFFSETOF(ByteArray, m_data); } diff --git a/Source/JavaScriptCore/wtf/CMakeLists.txt b/Source/JavaScriptCore/wtf/CMakeLists.txt index 52d3e3c4d..c22ae5185 100644 --- a/Source/JavaScriptCore/wtf/CMakeLists.txt +++ b/Source/JavaScriptCore/wtf/CMakeLists.txt @@ -53,6 +53,7 @@ SET(WTF_HEADERS Noncopyable.h NotFound.h NullPtr.h + NumberOfCores.h OSAllocator.h OSRandomSource.h OwnArrayPtr.h @@ -146,6 +147,7 @@ SET(WTF_SOURCES MainThread.cpp MD5.cpp OSRandomSource.cpp + NumberOfCores.cpp PageAllocationAligned.cpp PageBlock.cpp ParallelJobsGeneric.cpp diff --git a/Source/JavaScriptCore/wtf/CheckedBoolean.h b/Source/JavaScriptCore/wtf/CheckedBoolean.h new file mode 100644 index 000000000..c65c70ef8 --- /dev/null +++ b/Source/JavaScriptCore/wtf/CheckedBoolean.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 + * 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 CheckedBoolean_h +#define CheckedBoolean_h + +#include <wtf/Assertions.h> + +class CheckedBoolean { +public: + CheckedBoolean(bool value) + : m_value(value) +#if !ASSERT_DISABLED + , m_checked(false) +#endif + { + } + + ~CheckedBoolean() + { + ASSERT(m_checked); + } + + operator bool() + { +#if !ASSERT_DISABLED + m_checked = true; +#endif + return m_value; + } + +private: + bool m_value; +#if !ASSERT_DISABLED + bool m_checked; +#endif +}; + +#endif diff --git a/Source/JavaScriptCore/wtf/Compiler.h b/Source/JavaScriptCore/wtf/Compiler.h index 93d3316bf..96ad6e40e 100644 --- a/Source/JavaScriptCore/wtf/Compiler.h +++ b/Source/JavaScriptCore/wtf/Compiler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -239,4 +239,14 @@ #define FINAL #endif +/* OBJC_CLASS */ + +#ifndef OBJC_CLASS +#ifdef __OBJC__ +#define OBJC_CLASS @class +#else +#define OBJC_CLASS class +#endif +#endif + #endif /* WTF_Compiler_h */ diff --git a/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.h b/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.h index 348242e25..2262b6c3b 100644 --- a/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.h +++ b/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.h @@ -31,8 +31,8 @@ namespace WTF { #if USE(OS_RANDOMNESS) -uint32_t cryptographicallyRandomNumber(); -void cryptographicallyRandomValues(void* buffer, size_t length); +WTF_EXPORT_PRIVATE uint32_t cryptographicallyRandomNumber(); +WTF_EXPORT_PRIVATE void cryptographicallyRandomValues(void* buffer, size_t length); #endif } diff --git a/Source/JavaScriptCore/wtf/CurrentTime.h b/Source/JavaScriptCore/wtf/CurrentTime.h index 71775c273..ee49f8d25 100644 --- a/Source/JavaScriptCore/wtf/CurrentTime.h +++ b/Source/JavaScriptCore/wtf/CurrentTime.h @@ -39,7 +39,7 @@ namespace WTF { // Returns the current UTC time in seconds, counted from January 1, 1970. // Precision varies depending on platform but is usually as good or better // than a millisecond. -double currentTime(); +WTF_EXPORT_PRIVATE double currentTime(); // Same thing, in milliseconds. inline double currentTimeMS() @@ -60,7 +60,7 @@ inline void getLocalTime(const time_t* localTime, struct tm* localTM) // Provides a monotonically increasing time in seconds since an arbitrary point in the past. // On unsupported platforms, this function only guarantees the result will be non-decreasing. -double monotonicallyIncreasingTime(); +WTF_EXPORT_PRIVATE double monotonicallyIncreasingTime(); } // namespace WTF diff --git a/Source/JavaScriptCore/wtf/DateMath.h b/Source/JavaScriptCore/wtf/DateMath.h index 114acf8a8..fc1a8d8e4 100644 --- a/Source/JavaScriptCore/wtf/DateMath.h +++ b/Source/JavaScriptCore/wtf/DateMath.h @@ -61,7 +61,7 @@ int equivalentYearForDST(int year); // Not really math related, but this is currently the only shared place to put these. double parseES5DateFromNullTerminatedCharacters(const char* dateString); -double parseDateFromNullTerminatedCharacters(const char* dateString); +WTF_EXPORT_PRIVATE double parseDateFromNullTerminatedCharacters(const char* dateString); double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveTZ, int& offset); double timeClip(double); // dayOfWeek: [0, 6] 0 being Monday, day: [1, 31], month: [0, 11], year: ex: 2011, hours: [0, 23], minutes: [0, 59], seconds: [0, 59], utcOffset: [-720,720]. @@ -89,18 +89,18 @@ const double msPerMonth = 2592000000.0; bool isLeapYear(int year); // Returns the number of days from 1970-01-01 to the specified date. -double dateToDaysFrom1970(int year, int month, int day); -int msToYear(double ms); +WTF_EXPORT_PRIVATE double dateToDaysFrom1970(int year, int month, int day); +WTF_EXPORT_PRIVATE int msToYear(double ms); double msToDays(double ms); int msToMinutes(double ms); int msToHours(double ms); -int dayInYear(double ms, int year); -int monthFromDayInYear(int dayInYear, bool leapYear); -int dayInMonthFromDayInYear(int dayInYear, bool leapYear); +WTF_EXPORT_PRIVATE int dayInYear(double ms, int year); +WTF_EXPORT_PRIVATE int monthFromDayInYear(int dayInYear, bool leapYear); +WTF_EXPORT_PRIVATE int dayInMonthFromDayInYear(int dayInYear, bool leapYear); // Returns offset milliseconds for UTC and DST. -int32_t calculateUTCOffset(); -double calculateDSTOffset(double ms, double utcOffset); +WTF_EXPORT_PRIVATE int32_t calculateUTCOffset(); +WTF_EXPORT_PRIVATE double calculateDSTOffset(double ms, double utcOffset); } // namespace WTF diff --git a/Source/JavaScriptCore/wtf/DecimalNumber.h b/Source/JavaScriptCore/wtf/DecimalNumber.h index ac7b80058..61effcdd3 100644 --- a/Source/JavaScriptCore/wtf/DecimalNumber.h +++ b/Source/JavaScriptCore/wtf/DecimalNumber.h @@ -81,11 +81,11 @@ public: ASSERT(m_significand[0] != '0' || !m_exponent); } - unsigned bufferLengthForStringDecimal() const; - unsigned bufferLengthForStringExponential() const; + WTF_EXPORT_PRIVATE unsigned bufferLengthForStringDecimal() const; + WTF_EXPORT_PRIVATE unsigned bufferLengthForStringExponential() const; - unsigned toStringDecimal(UChar* buffer, unsigned bufferLength) const; - unsigned toStringExponential(UChar* buffer, unsigned bufferLength) const; + WTF_EXPORT_PRIVATE unsigned toStringDecimal(UChar* buffer, unsigned bufferLength) const; + WTF_EXPORT_PRIVATE unsigned toStringExponential(UChar* buffer, unsigned bufferLength) const; bool sign() const { return m_sign; } int exponent() const { return m_exponent; } diff --git a/Source/JavaScriptCore/wtf/DoublyLinkedList.h b/Source/JavaScriptCore/wtf/DoublyLinkedList.h index 18aa00e17..361d71d7b 100644 --- a/Source/JavaScriptCore/wtf/DoublyLinkedList.h +++ b/Source/JavaScriptCore/wtf/DoublyLinkedList.h @@ -77,6 +77,7 @@ public: T* head() const; T* removeHead(); + void push(T*); void append(T*); void remove(T*); @@ -115,6 +116,24 @@ template<typename T> inline T* DoublyLinkedList<T>::head() const return m_head; } +template<typename T> inline void DoublyLinkedList<T>::push(T* node) +{ + if (!m_head) { + ASSERT(!m_tail); + m_head = node; + m_tail = node; + node->setPrev(0); + node->setNext(0); + return; + } + + ASSERT(m_tail); + m_head->setPrev(node); + node->setNext(m_head); + node->setPrev(0); + m_head = node; +} + template<typename T> inline void DoublyLinkedList<T>::append(T* node) { if (!m_tail) { diff --git a/Source/JavaScriptCore/wtf/FastMalloc.cpp b/Source/JavaScriptCore/wtf/FastMalloc.cpp index 5c684500f..6b92f5542 100644 --- a/Source/JavaScriptCore/wtf/FastMalloc.cpp +++ b/Source/JavaScriptCore/wtf/FastMalloc.cpp @@ -182,7 +182,7 @@ namespace WTF { namespace Internal { #if !ENABLE(WTF_MALLOC_VALIDATION) -void fastMallocMatchFailed(void*); +WTF_EXPORT_PRIVATE void fastMallocMatchFailed(void*); #else COMPILE_ASSERT(((sizeof(ValidationHeader) % sizeof(AllocAlignmentInteger)) == 0), ValidationHeader_must_produce_correct_alignment); #endif @@ -400,7 +400,7 @@ size_t fastMallocSize(const void* p) #if OS(DARWIN) // This symbol is present in the JavaScriptCore exports file even when FastMalloc is disabled. // It will never be used in this case, so it's type and value are less interesting than its presence. -extern "C" const int jscore_fastmalloc_introspection = 0; +extern "C" WTF_EXPORT_PRIVATE const int jscore_fastmalloc_introspection = 0; #endif #else // FORCE_SYSTEM_MALLOC diff --git a/Source/JavaScriptCore/wtf/FastMalloc.h b/Source/JavaScriptCore/wtf/FastMalloc.h index b4f74e47b..b115908ba 100644 --- a/Source/JavaScriptCore/wtf/FastMalloc.h +++ b/Source/JavaScriptCore/wtf/FastMalloc.h @@ -29,12 +29,12 @@ namespace WTF { // These functions call CRASH() if an allocation fails. - void* fastMalloc(size_t); - void* fastZeroedMalloc(size_t); - void* fastCalloc(size_t numElements, size_t elementSize); - void* fastRealloc(void*, size_t); - char* fastStrDup(const char*); - size_t fastMallocSize(const void*); + WTF_EXPORT_PRIVATE void* fastMalloc(size_t); + WTF_EXPORT_PRIVATE void* fastZeroedMalloc(size_t); + WTF_EXPORT_PRIVATE void* fastCalloc(size_t numElements, size_t elementSize); + WTF_EXPORT_PRIVATE void* fastRealloc(void*, size_t); + WTF_EXPORT_PRIVATE char* fastStrDup(const char*); + WTF_EXPORT_PRIVATE size_t fastMallocSize(const void*); struct TryMallocReturnValue { TryMallocReturnValue(void* data) @@ -68,26 +68,26 @@ namespace WTF { return returnValue; } - TryMallocReturnValue tryFastMalloc(size_t n); + WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastMalloc(size_t n); TryMallocReturnValue tryFastZeroedMalloc(size_t n); - TryMallocReturnValue tryFastCalloc(size_t n_elements, size_t element_size); - TryMallocReturnValue tryFastRealloc(void* p, size_t n); + WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastCalloc(size_t n_elements, size_t element_size); + WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastRealloc(void* p, size_t n); - void fastFree(void*); + WTF_EXPORT_PRIVATE void fastFree(void*); #ifndef NDEBUG void fastMallocForbid(); void fastMallocAllow(); #endif - void releaseFastMallocFreeMemory(); + WTF_EXPORT_PRIVATE void releaseFastMallocFreeMemory(); struct FastMallocStatistics { size_t reservedVMBytes; size_t committedVMBytes; size_t freeListBytes; }; - FastMallocStatistics fastMallocStatistics(); + WTF_EXPORT_PRIVATE FastMallocStatistics fastMallocStatistics(); // This defines a type which holds an unsigned integer and is the same // size as the minimally aligned memory allocation. diff --git a/Source/JavaScriptCore/wtf/Forward.h b/Source/JavaScriptCore/wtf/Forward.h index 3c97849cc..b81ab2580 100644 --- a/Source/JavaScriptCore/wtf/Forward.h +++ b/Source/JavaScriptCore/wtf/Forward.h @@ -51,6 +51,7 @@ namespace WTF { class StringBuilder; class StringImpl; class Uint8Array; + class Uint8ClampedArray; class Uint16Array; class Uint32Array; } @@ -82,6 +83,7 @@ using WTF::StringBuffer; using WTF::StringBuilder; using WTF::StringImpl; using WTF::Uint8Array; +using WTF::Uint8ClampedArray; using WTF::Uint16Array; using WTF::Uint32Array; diff --git a/Source/JavaScriptCore/wtf/InlineASM.h b/Source/JavaScriptCore/wtf/InlineASM.h index c8a93f99c..379ebd364 100644 --- a/Source/JavaScriptCore/wtf/InlineASM.h +++ b/Source/JavaScriptCore/wtf/InlineASM.h @@ -44,6 +44,8 @@ #if (OS(LINUX) || OS(FREEBSD)) && CPU(X86_64) #define SYMBOL_STRING_RELOCATION(name) #name "@plt" +#elif OS(DARWIN) || (CPU(X86_64) && COMPILER(MINGW) && !GCC_VERSION_AT_LEAST(4, 5, 0)) +#define SYMBOL_STRING_RELOCATION(name) "_" #name #elif CPU(X86) && COMPILER(MINGW) #define SYMBOL_STRING_RELOCATION(name) "@" #name "@4" #else diff --git a/Source/JavaScriptCore/wtf/MD5.h b/Source/JavaScriptCore/wtf/MD5.h index 3caa810ba..ef027ccad 100644 --- a/Source/JavaScriptCore/wtf/MD5.h +++ b/Source/JavaScriptCore/wtf/MD5.h @@ -37,16 +37,16 @@ namespace WTF { class MD5 { public: - MD5(); + WTF_EXPORT_PRIVATE MD5(); void addBytes(const Vector<uint8_t>& input) { addBytes(input.data(), input.size()); } - void addBytes(const uint8_t* input, size_t length); + WTF_EXPORT_PRIVATE void addBytes(const uint8_t* input, size_t length); // checksum has a side effect of resetting the state of the object. - void checksum(Vector<uint8_t, 16>&); + WTF_EXPORT_PRIVATE void checksum(Vector<uint8_t, 16>&); private: uint32_t m_buf[4]; diff --git a/Source/JavaScriptCore/wtf/MainThread.h b/Source/JavaScriptCore/wtf/MainThread.h index c153d1eba..ff76a5fd3 100644 --- a/Source/JavaScriptCore/wtf/MainThread.h +++ b/Source/JavaScriptCore/wtf/MainThread.h @@ -40,21 +40,21 @@ typedef uint32_t ThreadIdentifier; typedef void MainThreadFunction(void*); // Must be called from the main thread. -void initializeMainThread(); +WTF_EXPORT_PRIVATE void initializeMainThread(); -void callOnMainThread(MainThreadFunction*, void* context); -void callOnMainThreadAndWait(MainThreadFunction*, void* context); -void cancelCallOnMainThread(MainThreadFunction*, void* context); +WTF_EXPORT_PRIVATE void callOnMainThread(MainThreadFunction*, void* context); +WTF_EXPORT_PRIVATE void callOnMainThreadAndWait(MainThreadFunction*, void* context); +WTF_EXPORT_PRIVATE void cancelCallOnMainThread(MainThreadFunction*, void* context); template<typename> class Function; -void callOnMainThread(const Function<void ()>&); +WTF_EXPORT_PRIVATE void callOnMainThread(const Function<void ()>&); -void setMainThreadCallbacksPaused(bool paused); +WTF_EXPORT_PRIVATE void setMainThreadCallbacksPaused(bool paused); -bool isMainThread(); +WTF_EXPORT_PRIVATE bool isMainThread(); #if ENABLE(PARALLEL_GC) void registerGCThread(); -bool isMainThreadOrGCThread(); +WTF_EXPORT_PRIVATE bool isMainThreadOrGCThread(); #elif PLATFORM(MAC) bool isMainThreadOrGCThread(); #else @@ -70,7 +70,7 @@ void dispatchFunctionsFromMainThread(); // This version of initializeMainThread sets up the main thread as corresponding // to the process's main thread, and not necessarily the thread that calls this // function. It should only be used as a legacy aid for Mac WebKit. -void initializeMainThreadToProcessMainThread(); +WTF_EXPORT_PRIVATE void initializeMainThreadToProcessMainThread(); void initializeMainThreadToProcessMainThreadPlatform(); #endif diff --git a/Source/JavaScriptCore/wtf/MetaAllocator.cpp b/Source/JavaScriptCore/wtf/MetaAllocator.cpp index 92205a5d8..d153faab7 100644 --- a/Source/JavaScriptCore/wtf/MetaAllocator.cpp +++ b/Source/JavaScriptCore/wtf/MetaAllocator.cpp @@ -33,10 +33,33 @@ namespace WTF { -MetaAllocatorHandle::MetaAllocatorHandle(MetaAllocator* allocator, void* start, size_t sizeInBytes) +void MetaAllocatorTracker::notify(MetaAllocatorHandle* handle) +{ + m_allocations.insert(handle); +} + +void MetaAllocatorTracker::release(MetaAllocatorHandle* handle) +{ + m_allocations.remove(handle); +} + +ALWAYS_INLINE void MetaAllocator::release(MetaAllocatorHandle* handle) +{ + SpinLockHolder locker(&m_lock); + if (handle->sizeInBytes()) { + decrementPageOccupancy(handle->start(), handle->sizeInBytes()); + addFreeSpaceFromReleasedHandle(handle->start(), handle->sizeInBytes()); + } + + if (UNLIKELY(!!m_tracker)) + m_tracker->release(handle); +} + +MetaAllocatorHandle::MetaAllocatorHandle(MetaAllocator* allocator, void* start, size_t sizeInBytes, void* ownerUID) : m_allocator(allocator) , m_start(start) , m_sizeInBytes(sizeInBytes) + , m_ownerUID(ownerUID) { ASSERT(allocator); ASSERT(start); @@ -45,24 +68,14 @@ MetaAllocatorHandle::MetaAllocatorHandle(MetaAllocator* allocator, void* start, MetaAllocatorHandle::~MetaAllocatorHandle() { - if (!m_allocator) - return; - SpinLockHolder locker(&m_allocator->m_lock); - if (m_sizeInBytes) { - m_allocator->decrementPageOccupancy(m_start, m_sizeInBytes); - m_allocator->addFreeSpaceFromReleasedHandle(m_start, m_sizeInBytes); - } + ASSERT(m_allocator); + m_allocator->release(this); } void MetaAllocatorHandle::shrink(size_t newSizeInBytes) { ASSERT(newSizeInBytes <= m_sizeInBytes); - if (!m_allocator) { - m_sizeInBytes = newSizeInBytes; - return; - } - SpinLockHolder locker(&m_allocator->m_lock); newSizeInBytes = m_allocator->roundUp(newSizeInBytes); @@ -91,6 +104,7 @@ MetaAllocator::MetaAllocator(size_t allocationGranule) , m_bytesAllocated(0) , m_bytesReserved(0) , m_bytesCommitted(0) + , m_tracker(0) #ifndef NDEBUG , m_mallocBalance(0) #endif @@ -116,7 +130,7 @@ MetaAllocator::MetaAllocator(size_t allocationGranule) ASSERT(static_cast<size_t>(1) << m_logAllocationGranule == m_allocationGranule); } -PassRefPtr<MetaAllocatorHandle> MetaAllocator::allocate(size_t sizeInBytes) +PassRefPtr<MetaAllocatorHandle> MetaAllocator::allocate(size_t sizeInBytes, void* ownerUID) { SpinLockHolder locker(&m_lock); @@ -154,10 +168,13 @@ PassRefPtr<MetaAllocatorHandle> MetaAllocator::allocate(size_t sizeInBytes) m_numAllocations++; #endif - MetaAllocatorHandle* handle = new MetaAllocatorHandle(this, start, sizeInBytes); + MetaAllocatorHandle* handle = new MetaAllocatorHandle(this, start, sizeInBytes, ownerUID); // FIXME: Implement a verifier scheme that groks MetaAllocatorHandles handle->deprecatedTurnOffVerifier(); + if (UNLIKELY(!!m_tracker)) + m_tracker->notify(handle); + return adoptRef(handle); } @@ -178,18 +195,18 @@ void* MetaAllocator::findAndRemoveFreeSpace(size_t sizeInBytes) if (!node) return 0; - ASSERT(node->m_key >= sizeInBytes); + ASSERT(node->m_sizeInBytes >= sizeInBytes); m_freeSpaceSizeMap.remove(node); void* result; - if (node->m_key == sizeInBytes) { + if (node->m_sizeInBytes == sizeInBytes) { // Easy case: perfect fit, so just remove the node entirely. - result = node->m_value; + result = node->m_start; - m_freeSpaceStartAddressMap.remove(node->m_value); - m_freeSpaceEndAddressMap.remove(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_value) + node->m_key)); + m_freeSpaceStartAddressMap.remove(node->m_start); + m_freeSpaceEndAddressMap.remove(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_start) + node->m_sizeInBytes)); freeFreeSpaceNode(node); } else { // Try to be a good citizen and ensure that the returned chunk of memory @@ -199,31 +216,31 @@ void* MetaAllocator::findAndRemoveFreeSpace(size_t sizeInBytes) // of committed pages, since in the long run, smaller fragmentation means // fewer committed pages and fewer failures in general. - uintptr_t firstPage = reinterpret_cast<uintptr_t>(node->m_value) >> m_logPageSize; - uintptr_t lastPage = (reinterpret_cast<uintptr_t>(node->m_value) + node->m_key - 1) >> m_logPageSize; + uintptr_t firstPage = reinterpret_cast<uintptr_t>(node->m_start) >> m_logPageSize; + uintptr_t lastPage = (reinterpret_cast<uintptr_t>(node->m_start) + node->m_sizeInBytes - 1) >> m_logPageSize; - uintptr_t lastPageForLeftAllocation = (reinterpret_cast<uintptr_t>(node->m_value) + sizeInBytes - 1) >> m_logPageSize; - uintptr_t firstPageForRightAllocation = (reinterpret_cast<uintptr_t>(node->m_value) + node->m_key - sizeInBytes) >> m_logPageSize; + uintptr_t lastPageForLeftAllocation = (reinterpret_cast<uintptr_t>(node->m_start) + sizeInBytes - 1) >> m_logPageSize; + uintptr_t firstPageForRightAllocation = (reinterpret_cast<uintptr_t>(node->m_start) + node->m_sizeInBytes - sizeInBytes) >> m_logPageSize; if (lastPageForLeftAllocation - firstPage + 1 <= lastPage - firstPageForRightAllocation + 1) { // Allocate in the left side of the returned chunk, and slide the node to the right. - result = node->m_value; + result = node->m_start; - m_freeSpaceStartAddressMap.remove(node->m_value); + m_freeSpaceStartAddressMap.remove(node->m_start); - node->m_key -= sizeInBytes; - node->m_value = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_value) + sizeInBytes); + node->m_sizeInBytes -= sizeInBytes; + node->m_start = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_start) + sizeInBytes); m_freeSpaceSizeMap.insert(node); - m_freeSpaceStartAddressMap.add(node->m_value, node); + m_freeSpaceStartAddressMap.add(node->m_start, node); } else { // Allocate in the right size of the returned chunk, and slide the node to the left; - result = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_value) + node->m_key - sizeInBytes); + result = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_start) + node->m_sizeInBytes - sizeInBytes); - m_freeSpaceEndAddressMap.remove(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_value) + node->m_key)); + m_freeSpaceEndAddressMap.remove(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_start) + node->m_sizeInBytes)); - node->m_key -= sizeInBytes; + node->m_sizeInBytes -= sizeInBytes; m_freeSpaceSizeMap.insert(node); m_freeSpaceEndAddressMap.add(result, node); @@ -255,7 +272,7 @@ size_t MetaAllocator::debugFreeSpaceSize() SpinLockHolder locker(&m_lock); size_t result = 0; for (FreeSpaceNode* node = m_freeSpaceSizeMap.first(); node; node = node->successor()) - result += node->m_key; + result += node->m_sizeInBytes; return result; #else CRASH(); @@ -274,12 +291,12 @@ void MetaAllocator::addFreeSpace(void* start, size_t sizeInBytes) // We have something we can coalesce with on the left. Remove it from the tree, and // remove its end from the end address map. - ASSERT(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(leftNeighbor->second->m_value) + leftNeighbor->second->m_key) == leftNeighbor->first); + ASSERT(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(leftNeighbor->second->m_start) + leftNeighbor->second->m_sizeInBytes) == leftNeighbor->first); FreeSpaceNode* leftNode = leftNeighbor->second; - void* leftStart = leftNode->m_value; - size_t leftSize = leftNode->m_key; + void* leftStart = leftNode->m_start; + size_t leftSize = leftNode->m_sizeInBytes; void* leftEnd = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(leftStart) + leftSize); ASSERT(leftEnd == start); @@ -292,11 +309,11 @@ void MetaAllocator::addFreeSpace(void* start, size_t sizeInBytes) // Freeing something in the middle of free blocks. Coalesce both left and // right, whilst removing the right neighbor from the maps. - ASSERT(rightNeighbor->second->m_value == rightNeighbor->first); + ASSERT(rightNeighbor->second->m_start == rightNeighbor->first); FreeSpaceNode* rightNode = rightNeighbor->second; void* rightStart = rightNeighbor->first; - size_t rightSize = rightNode->m_key; + size_t rightSize = rightNode->m_sizeInBytes; void* rightEnd = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(rightStart) + rightSize); ASSERT(rightStart == end); @@ -308,12 +325,12 @@ void MetaAllocator::addFreeSpace(void* start, size_t sizeInBytes) freeFreeSpaceNode(rightNode); - leftNode->m_key += sizeInBytes + rightSize; + leftNode->m_sizeInBytes += sizeInBytes + rightSize; m_freeSpaceSizeMap.insert(leftNode); m_freeSpaceEndAddressMap.add(rightEnd, leftNode); } else { - leftNode->m_key += sizeInBytes; + leftNode->m_sizeInBytes += sizeInBytes; m_freeSpaceSizeMap.insert(leftNode); m_freeSpaceEndAddressMap.add(end, leftNode); @@ -324,7 +341,7 @@ void MetaAllocator::addFreeSpace(void* start, size_t sizeInBytes) if (rightNeighbor != m_freeSpaceStartAddressMap.end()) { FreeSpaceNode* rightNode = rightNeighbor->second; void* rightStart = rightNeighbor->first; - size_t rightSize = rightNode->m_key; + size_t rightSize = rightNode->m_sizeInBytes; void* rightEnd = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(rightStart) + rightSize); ASSERT(rightStart == end); @@ -333,8 +350,8 @@ void MetaAllocator::addFreeSpace(void* start, size_t sizeInBytes) m_freeSpaceSizeMap.remove(rightNode); m_freeSpaceStartAddressMap.remove(rightStart); - rightNode->m_key += sizeInBytes; - rightNode->m_value = start; + rightNode->m_sizeInBytes += sizeInBytes; + rightNode->m_start = start; m_freeSpaceSizeMap.insert(rightNode); m_freeSpaceStartAddressMap.add(start, rightNode); @@ -343,8 +360,8 @@ void MetaAllocator::addFreeSpace(void* start, size_t sizeInBytes) FreeSpaceNode* node = allocFreeSpaceNode(); - node->m_key = sizeInBytes; - node->m_value = start; + node->m_sizeInBytes = sizeInBytes; + node->m_start = start; m_freeSpaceSizeMap.insert(node); m_freeSpaceStartAddressMap.add(start, node); diff --git a/Source/JavaScriptCore/wtf/MetaAllocator.h b/Source/JavaScriptCore/wtf/MetaAllocator.h index cf971b720..ffd55667e 100644 --- a/Source/JavaScriptCore/wtf/MetaAllocator.h +++ b/Source/JavaScriptCore/wtf/MetaAllocator.h @@ -43,15 +43,36 @@ namespace WTF { #define ENABLE_META_ALLOCATOR_PROFILE 0 +class MetaAllocatorTracker { +public: + void notify(MetaAllocatorHandle*); + void release(MetaAllocatorHandle*); + + MetaAllocatorHandle* find(void* address) + { + MetaAllocatorHandle* handle = m_allocations.findGreatestLessThanOrEqual(address); + if (handle && address < handle->end()) + return handle; + return 0; + } + + RedBlackTree<MetaAllocatorHandle, void*> m_allocations; +}; + class MetaAllocator { WTF_MAKE_NONCOPYABLE(MetaAllocator); + public: - - MetaAllocator(size_t allocationGranule); + WTF_EXPORT_PRIVATE MetaAllocator(size_t allocationGranule); virtual ~MetaAllocator(); - PassRefPtr<MetaAllocatorHandle> allocate(size_t sizeInBytes); + WTF_EXPORT_PRIVATE PassRefPtr<MetaAllocatorHandle> allocate(size_t sizeInBytes, void* ownerUID); + + void trackAllocations(MetaAllocatorTracker* tracker) + { + m_tracker = tracker; + } // Non-atomic methods for getting allocator statistics. size_t bytesAllocated() { return m_bytesAllocated; } @@ -69,11 +90,11 @@ public: // Add more free space to the allocator. Call this directly from // the constructor if you wish to operate the allocator within a // fixed pool. - void addFreshFreeSpace(void* start, size_t sizeInBytes); + WTF_EXPORT_PRIVATE void addFreshFreeSpace(void* start, size_t sizeInBytes); // This is meant only for implementing tests. Never call this in release // builds. - size_t debugFreeSpaceSize(); + WTF_EXPORT_PRIVATE size_t debugFreeSpaceSize(); #if ENABLE(META_ALLOCATOR_PROFILE) void dumpProfile(); @@ -101,8 +122,26 @@ private: friend class MetaAllocatorHandle; - typedef RedBlackTree<size_t, void*> Tree; - typedef Tree::Node FreeSpaceNode; + class FreeSpaceNode : public RedBlackTree<FreeSpaceNode, size_t>::Node { + public: + FreeSpaceNode(void* start, size_t sizeInBytes) + : m_start(start) + , m_sizeInBytes(sizeInBytes) + { + } + + size_t key() + { + return m_sizeInBytes; + } + + void* m_start; + size_t m_sizeInBytes; + }; + typedef RedBlackTree<FreeSpaceNode, size_t> Tree; + + // Release a MetaAllocatorHandle. + void release(MetaAllocatorHandle*); // Remove free space from the allocator. This is effectively // the allocate() function, except that it does not mark the @@ -121,13 +160,13 @@ private: void incrementPageOccupancy(void* address, size_t sizeInBytes); void decrementPageOccupancy(void* address, size_t sizeInBytes); - + // Utilities. size_t roundUp(size_t sizeInBytes); FreeSpaceNode* allocFreeSpaceNode(); - void freeFreeSpaceNode(FreeSpaceNode*); + WTF_EXPORT_PRIVATE void freeFreeSpaceNode(FreeSpaceNode*); size_t m_allocationGranule; unsigned m_logAllocationGranule; @@ -145,6 +184,8 @@ private: SpinLock m_lock; + MetaAllocatorTracker* m_tracker; + #ifndef NDEBUG size_t m_mallocBalance; #endif diff --git a/Source/JavaScriptCore/wtf/MetaAllocatorHandle.h b/Source/JavaScriptCore/wtf/MetaAllocatorHandle.h index 5a32081d4..c43f491f3 100644 --- a/Source/JavaScriptCore/wtf/MetaAllocatorHandle.h +++ b/Source/JavaScriptCore/wtf/MetaAllocatorHandle.h @@ -30,6 +30,7 @@ #define WTF_MetaAllocatorHandle_h #include <wtf/Assertions.h> +#include <wtf/RedBlackTree.h> #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> @@ -37,25 +38,12 @@ namespace WTF { class MetaAllocator; -class MetaAllocatorHandle : public RefCounted<MetaAllocatorHandle> { +class MetaAllocatorHandle : public RefCounted<MetaAllocatorHandle>, public RedBlackTree<MetaAllocatorHandle, void*>::Node { private: - MetaAllocatorHandle(MetaAllocator*, void* start, size_t sizeInBytes); - - MetaAllocatorHandle(void* start, size_t sizeInBytes) - : m_allocator(0) - , m_start(start) - , m_sizeInBytes(sizeInBytes) - { - ASSERT(start); - } + MetaAllocatorHandle(MetaAllocator*, void* start, size_t sizeInBytes, void* ownerUID); public: - ~MetaAllocatorHandle(); - - static PassRefPtr<MetaAllocatorHandle> createSelfManagedHandle(void* start, size_t sizeInBytes) - { - return adoptRef(new MetaAllocatorHandle(start, sizeInBytes)); - } + WTF_EXPORT_PRIVATE ~MetaAllocatorHandle(); void* start() { @@ -72,7 +60,7 @@ public: return m_sizeInBytes; } - void shrink(size_t newSizeInBytes); + WTF_EXPORT_PRIVATE void shrink(size_t newSizeInBytes); bool isManaged() { @@ -84,6 +72,16 @@ public: ASSERT(m_allocator); return m_allocator; } + + void* ownerUID() + { + return m_ownerUID; + } + + void* key() + { + return m_start; + } private: friend class MetaAllocator; @@ -91,6 +89,7 @@ private: MetaAllocator* m_allocator; void* m_start; size_t m_sizeInBytes; + void* m_ownerUID; }; } diff --git a/Source/JavaScriptCore/wtf/NumberOfCores.cpp b/Source/JavaScriptCore/wtf/NumberOfCores.cpp new file mode 100644 index 000000000..1e7f45f5c --- /dev/null +++ b/Source/JavaScriptCore/wtf/NumberOfCores.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 University of Szeged. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "NumberOfCores.h" + +#if OS(DARWIN) || OS(OPENBSD) || OS(NETBSD) || OS(FREEBSD) +#include <sys/sysctl.h> +#include <sys/types.h> +#elif OS(LINUX) || OS(AIX) || OS(SOLARIS) +#include <unistd.h> +#elif OS(WINDOWS) +#include <windows.h> +#include <wtf/UnusedParam.h> +#endif + +namespace WTF { + +int numberOfProcessorCores() +{ + const int defaultIfUnavailable = 1; + static int s_numberOfCores = -1; + + if (s_numberOfCores > 0) + return s_numberOfCores; + +#if OS(DARWIN) || OS(OPENBSD) || OS(NETBSD) || OS(FREEBSD) + unsigned result; + size_t length = sizeof(result); + int name[] = { + CTL_HW, + HW_NCPU + }; + int sysctlResult = sysctl(name, sizeof(name) / sizeof(int), &result, &length, 0, 0); + + s_numberOfCores = sysctlResult < 0 ? defaultIfUnavailable : result; +#elif OS(LINUX) || OS(AIX) || OS(SOLARIS) + long sysconfResult = sysconf(_SC_NPROCESSORS_ONLN); + + s_numberOfCores = sysconfResult < 0 ? defaultIfUnavailable : static_cast<int>(sysconfResult); +#elif OS(WINDOWS) + UNUSED_PARAM(defaultIfUnavailable); + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + + s_numberOfCores = sysInfo.dwNumberOfProcessors; +#else + s_numberOfCores = defaultIfUnavailable; +#endif + return s_numberOfCores; +} + +} diff --git a/Source/JavaScriptCore/wtf/NumberOfCores.h b/Source/JavaScriptCore/wtf/NumberOfCores.h new file mode 100644 index 000000000..8bc8d9455 --- /dev/null +++ b/Source/JavaScriptCore/wtf/NumberOfCores.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 University of Szeged. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef NumberOfCores_h +#define NumberOfCores_h + +namespace WTF { + +int numberOfProcessorCores(); + +} + +#endif diff --git a/Source/JavaScriptCore/wtf/OSAllocator.h b/Source/JavaScriptCore/wtf/OSAllocator.h index bf9f04968..9ea4f6b51 100644 --- a/Source/JavaScriptCore/wtf/OSAllocator.h +++ b/Source/JavaScriptCore/wtf/OSAllocator.h @@ -26,6 +26,7 @@ #ifndef OSAllocator_h #define OSAllocator_h +#include <algorithm> #include <wtf/UnusedParam.h> #include <wtf/VMTags.h> #include <wtf/VMTags.h> @@ -46,7 +47,7 @@ public: // releaseDecommitted should be called on a region of VM allocated by a single reservation, // the memory must all currently be in a decommitted state. static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false, bool includesGuardPages = false); - static void releaseDecommitted(void*, size_t); + WTF_EXPORT_PRIVATE static void releaseDecommitted(void*, size_t); // These methods are symmetric; they commit or decommit a region of VM (uncommitted VM should // never be accessed, since the OS may not have attached physical memory for these regions). @@ -57,7 +58,7 @@ public: // These methods are symmetric; reserveAndCommit allocates VM in an committed state, // decommitAndRelease should be called on a region of VM allocated by a single reservation, // the memory must all currently be in a committed state. - static void* reserveAndCommit(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false, bool includesGuardPages = false); + WTF_EXPORT_PRIVATE static void* reserveAndCommit(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false, bool includesGuardPages = false); static void decommitAndRelease(void* base, size_t size); // These methods are akin to reserveAndCommit/decommitAndRelease, above - however rather than @@ -65,6 +66,12 @@ public: // specified. static void* reserveAndCommit(size_t reserveSize, size_t commitSize, Usage = UnknownUsage, bool writable = true, bool executable = false); static void decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize); + + // Reallocate an existing, committed allocation. + // The prior allocation must be fully comitted, and the new size will also be fully committed. + // This interface is provided since it may be possible to optimize this operation on some platforms. + template<typename T> + static T* reallocateCommitted(T*, size_t oldSize, size_t newSize, Usage = UnknownUsage, bool writable = true, bool executable = false); }; inline void* OSAllocator::reserveAndCommit(size_t reserveSize, size_t commitSize, Usage usage, bool writable, bool executable) @@ -93,6 +100,15 @@ inline void OSAllocator::decommitAndRelease(void* base, size_t size) decommitAndRelease(base, size, base, size); } +template<typename T> +inline T* OSAllocator::reallocateCommitted(T* oldBase, size_t oldSize, size_t newSize, Usage usage, bool writable, bool executable) +{ + void* newBase = reserveAndCommit(newSize, usage, writable, executable); + memcpy(newBase, oldBase, std::min(oldSize, newSize)); + decommitAndRelease(oldBase, oldSize); + return static_cast<T*>(newBase); +} + } // namespace WTF using WTF::OSAllocator; diff --git a/Source/JavaScriptCore/wtf/OSAllocatorPosix.cpp b/Source/JavaScriptCore/wtf/OSAllocatorPosix.cpp index b264f685a..56c6089ff 100644 --- a/Source/JavaScriptCore/wtf/OSAllocatorPosix.cpp +++ b/Source/JavaScriptCore/wtf/OSAllocatorPosix.cpp @@ -37,7 +37,9 @@ namespace WTF { void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages) { void* result = reserveAndCommit(bytes, usage, writable, executable, includesGuardPages); -#if HAVE(MADV_FREE_REUSE) +#if OS(QNX) + posix_madvise(result, bytes, POSIX_MADV_DONTNEED); +#elif HAVE(MADV_FREE_REUSE) // To support the "reserve then commit" model, we have to initially decommit. while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } #endif @@ -120,7 +122,9 @@ void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bo void OSAllocator::commit(void* address, size_t bytes, bool, bool) { -#if HAVE(MADV_FREE_REUSE) +#if OS(QNX) + posix_madvise(address, bytes, POSIX_MADV_WILLNEED); +#elif HAVE(MADV_FREE_REUSE) while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { } #else // Non-MADV_FREE_REUSE reservations automatically commit on demand. @@ -131,7 +135,9 @@ void OSAllocator::commit(void* address, size_t bytes, bool, bool) void OSAllocator::decommit(void* address, size_t bytes) { -#if HAVE(MADV_FREE_REUSE) +#if OS(QNX) + posix_madvise(address, bytes, POSIX_MADV_DONTNEED); +#elif HAVE(MADV_FREE_REUSE) while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } #elif HAVE(MADV_FREE) while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { } diff --git a/Source/JavaScriptCore/wtf/OwnPtrCommon.h b/Source/JavaScriptCore/wtf/OwnPtrCommon.h index 16283aed2..315db8954 100644 --- a/Source/JavaScriptCore/wtf/OwnPtrCommon.h +++ b/Source/JavaScriptCore/wtf/OwnPtrCommon.h @@ -28,7 +28,7 @@ #ifndef WTF_OwnPtrCommon_h #define WTF_OwnPtrCommon_h -#if PLATFORM(WIN) +#if OS(WINDOWS) typedef struct HBITMAP__* HBITMAP; typedef struct HBRUSH__* HBRUSH; typedef struct HDC__* HDC; @@ -41,6 +41,7 @@ typedef struct HRGN__* HRGN; #if PLATFORM(EFL) typedef struct _Ecore_Evas Ecore_Evas; typedef struct _Ecore_Pipe Ecore_Pipe; +typedef struct _Eina_Module Eina_Module; typedef struct _Evas_Object Evas_Object; #endif @@ -53,7 +54,7 @@ namespace WTF { delete ptr; } -#if PLATFORM(WIN) +#if OS(WINDOWS) void deleteOwnedPtr(HBITMAP); void deleteOwnedPtr(HBRUSH); void deleteOwnedPtr(HDC); @@ -66,6 +67,7 @@ namespace WTF { #if PLATFORM(EFL) void deleteOwnedPtr(Ecore_Evas*); void deleteOwnedPtr(Ecore_Pipe*); + void deleteOwnedPtr(Eina_Module*); void deleteOwnedPtr(Evas_Object*); #endif diff --git a/Source/JavaScriptCore/wtf/PageBlock.h b/Source/JavaScriptCore/wtf/PageBlock.h index e17c5460a..3c348a0e3 100644 --- a/Source/JavaScriptCore/wtf/PageBlock.h +++ b/Source/JavaScriptCore/wtf/PageBlock.h @@ -28,7 +28,7 @@ namespace WTF { -size_t pageSize(); +WTF_EXPORT_PRIVATE size_t pageSize(); inline bool isPageAligned(void* address) { return !(reinterpret_cast<intptr_t>(address) & (pageSize() - 1)); } inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); } inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); } diff --git a/Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp b/Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp index b6207dc88..fd5b1f847 100644 --- a/Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp +++ b/Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp @@ -30,34 +30,22 @@ #if ENABLE(THREADING_GENERIC) #include "ParallelJobs.h" -#include "UnusedParam.h" - -#if OS(DARWIN) || OS(OPENBSD) || OS(NETBSD) -#include <sys/sysctl.h> -#include <sys/types.h> -#elif OS(LINUX) || OS(AIX) || OS(SOLARIS) -#include <unistd.h> -#elif OS(WINDOWS) -#include <windows.h> -#endif +#include <wtf/NumberOfCores.h> namespace WTF { Vector< RefPtr<ParallelEnvironment::ThreadPrivate> >* ParallelEnvironment::s_threadPool = 0; -int ParallelEnvironment::s_maxNumberOfParallelThreads = -1; - ParallelEnvironment::ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, int requestedJobNumber) : m_threadFunction(threadFunction), m_sizeOfParameter(sizeOfParameter) { ASSERT_ARG(requestedJobNumber, requestedJobNumber >= 1); - if (s_maxNumberOfParallelThreads == -1) - determineMaxNumberOfParallelThreads(); + int maxNumberOfCores = numberOfProcessorCores(); - if (!requestedJobNumber || requestedJobNumber > s_maxNumberOfParallelThreads) - requestedJobNumber = static_cast<unsigned>(s_maxNumberOfParallelThreads); + if (!requestedJobNumber || requestedJobNumber > maxNumberOfCores) + requestedJobNumber = static_cast<unsigned>(maxNumberOfCores); if (!s_threadPool) s_threadPool = new Vector< RefPtr<ThreadPrivate> >(); @@ -65,7 +53,7 @@ ParallelEnvironment::ParallelEnvironment(ThreadFunction threadFunction, size_t s // The main thread should be also a worker. int maxNumberOfNewThreads = requestedJobNumber - 1; - for (int i = 0; i < s_maxNumberOfParallelThreads && m_threads.size() < static_cast<unsigned>(maxNumberOfNewThreads); ++i) { + for (int i = 0; i < maxNumberOfCores && m_threads.size() < static_cast<unsigned>(maxNumberOfNewThreads); ++i) { if (s_threadPool->size() < static_cast<unsigned>(i) + 1U) s_threadPool->append(ThreadPrivate::create()); @@ -93,32 +81,6 @@ void ParallelEnvironment::execute(void* parameters) m_threads[i]->waitForFinish(); } -void ParallelEnvironment::determineMaxNumberOfParallelThreads() -{ - const int defaultIfUnavailable = 2; -#if OS(DARWIN) || OS(OPENBSD) || OS(NETBSD) - unsigned result; - size_t length = sizeof(result); - int name[] = { - CTL_HW, - HW_NCPU - }; - int sysctlResult = sysctl(name, sizeof(name) / sizeof(int), &result, &length, 0, 0); - s_maxNumberOfParallelThreads = sysctlResult < 0 ? defaultIfUnavailable : result; -#elif OS(LINUX) || OS(AIX) || OS(SOLARIS) - long sysconfResult = sysconf(_SC_NPROCESSORS_ONLN); - s_maxNumberOfParallelThreads = sysconfResult < 0 ? defaultIfUnavailable : static_cast<int>(sysconfResult); -#elif OS(WINDOWS) - UNUSED_PARAM(defaultIfUnavailable); - - SYSTEM_INFO sysInfo; - GetSystemInfo(&sysInfo); - s_maxNumberOfParallelThreads = sysInfo.dwNumberOfProcessors; -#else - s_maxNumberOfParallelThreads = defaultIfUnavailable; -#endif -} - bool ParallelEnvironment::ThreadPrivate::tryLockFor(ParallelEnvironment* parent) { bool locked = m_mutex.tryLock(); diff --git a/Source/JavaScriptCore/wtf/ParallelJobsGeneric.h b/Source/JavaScriptCore/wtf/ParallelJobsGeneric.h index dab6dd9fb..1c7d63c16 100644 --- a/Source/JavaScriptCore/wtf/ParallelJobsGeneric.h +++ b/Source/JavaScriptCore/wtf/ParallelJobsGeneric.h @@ -84,15 +84,12 @@ public: }; private: - static void determineMaxNumberOfParallelThreads(); - ThreadFunction m_threadFunction; size_t m_sizeOfParameter; int m_numberOfJobs; Vector< RefPtr<ThreadPrivate> > m_threads; static Vector< RefPtr<ThreadPrivate> >* s_threadPool; - static int s_maxNumberOfParallelThreads; }; } // namespace WTF diff --git a/Source/JavaScriptCore/wtf/Platform.h b/Source/JavaScriptCore/wtf/Platform.h index bb1462e1e..cecd5ddcd 100644 --- a/Source/JavaScriptCore/wtf/Platform.h +++ b/Source/JavaScriptCore/wtf/Platform.h @@ -386,6 +386,9 @@ #define WTF_OS_WINDOWS 1 #endif +#define WTF_OS_WIN ERROR "USE WINDOWS WITH OS NOT WIN" +#define WTF_OS_MAC ERROR "USE MAC_OS_X WITH OS NOT MAC" + /* OS(UNIX) - Any Unix-like system */ #if OS(AIX) \ || OS(ANDROID) \ @@ -543,7 +546,9 @@ #define ENABLE_SMOOTH_SCROLLING 1 #define ENABLE_WEB_ARCHIVE 1 #define ENABLE_WEB_AUDIO 1 +#if defined(ENABLE_VIDEO) #define ENABLE_VIDEO_TRACK 1 +#endif #endif /* PLATFORM(MAC) && !PLATFORM(IOS) */ #if PLATFORM(CHROMIUM) && OS(DARWIN) @@ -667,7 +672,7 @@ #endif #endif -#if !OS(WINDOWS) && !OS(SOLARIS) && !OS(QNX) \ +#if !OS(WINDOWS) && !OS(SOLARIS) \ && !OS(RVCT) \ && !OS(ANDROID) #define HAVE_TM_GMTOFF 1 @@ -721,6 +726,8 @@ #define HAVE_ERRNO_H 1 #define HAVE_MMAP 1 +#define HAVE_MADV_FREE_REUSE 1 +#define HAVE_MADV_FREE 1 #define HAVE_SBRK 1 #define HAVE_STRINGS_H 1 #define HAVE_SYS_PARAM_H 1 @@ -1159,5 +1166,8 @@ /* Using V8 implies not using JSC and vice versa */ #define WTF_USE_JSC !WTF_USE_V8 +#if ENABLE(NOTIFICATIONS) && PLATFORM(MAC) +#define ENABLE_TEXT_NOTIFICATIONS_ONLY 1 +#endif #endif /* WTF_Platform_h */ diff --git a/Source/JavaScriptCore/wtf/PlatformEfl.cmake b/Source/JavaScriptCore/wtf/PlatformEfl.cmake index 5805c4180..3887ead8c 100644 --- a/Source/JavaScriptCore/wtf/PlatformEfl.cmake +++ b/Source/JavaScriptCore/wtf/PlatformEfl.cmake @@ -31,6 +31,7 @@ LIST(APPEND WTF_LIBRARIES ${ICU_I18N_LIBRARIES} ${ECORE_LIBRARIES} ${ECORE_EVAS_LIBRARIES} + ${EINA_LIBRARIES} ${EVAS_LIBRARIES} ${CMAKE_DL_LIBS} ) diff --git a/Source/JavaScriptCore/wtf/RandomNumber.h b/Source/JavaScriptCore/wtf/RandomNumber.h index f2e7e8f50..76b223582 100644 --- a/Source/JavaScriptCore/wtf/RandomNumber.h +++ b/Source/JavaScriptCore/wtf/RandomNumber.h @@ -30,7 +30,7 @@ namespace WTF { // Returns a pseudo-random number in the range [0, 1), attempts to be // cryptographically secure if possible on the target platform - double randomNumber(); + WTF_EXPORT_PRIVATE double randomNumber(); } diff --git a/Source/JavaScriptCore/wtf/RedBlackTree.h b/Source/JavaScriptCore/wtf/RedBlackTree.h index af4e5c88a..19460c141 100644 --- a/Source/JavaScriptCore/wtf/RedBlackTree.h +++ b/Source/JavaScriptCore/wtf/RedBlackTree.h @@ -41,7 +41,7 @@ namespace WTF { // reference to this node. // - The key type must implement operator< and ==. -template<typename KeyType, typename ValueType> +template<class NodeType, typename KeyType> class RedBlackTree { WTF_MAKE_NONCOPYABLE(RedBlackTree); private: @@ -55,18 +55,12 @@ public: friend class RedBlackTree; public: - Node(KeyType key, ValueType value) - : m_key(key) - , m_value(value) - { - } - - const Node* successor() const + const NodeType* successor() const { const Node* x = this; if (x->right()) return treeMinimum(x->right()); - const Node* y = x->parent(); + const NodeType* y = x->parent(); while (y && x == y->right()) { x = y; y = y->parent(); @@ -74,12 +68,12 @@ public: return y; } - const Node* predecessor() const + const NodeType* predecessor() const { const Node* x = this; if (x->left()) return treeMaximum(x->left()); - const Node* y = x->parent(); + const NodeType* y = x->parent(); while (y && x == y->left()) { x = y; y = y->parent(); @@ -87,18 +81,15 @@ public: return y; } - Node* successor() + NodeType* successor() { - return const_cast<Node*>(const_cast<const Node*>(this)->successor()); + return const_cast<NodeType*>(const_cast<const Node*>(this)->successor()); } - - Node* predecessor() + + NodeType* predecessor() { - return const_cast<Node*>(const_cast<const Node*>(this)->predecessor()); + return const_cast<NodeType*>(const_cast<const Node*>(this)->predecessor()); } - - KeyType m_key; - ValueType m_value; private: void reset() @@ -110,32 +101,32 @@ public: // NOTE: these methods should pack the parent and red into a single // word. But doing so appears to reveal a bug in the compiler. - Node* parent() const + NodeType* parent() const { - return reinterpret_cast<Node*>(m_parentAndRed & ~static_cast<uintptr_t>(1)); + return reinterpret_cast<NodeType*>(m_parentAndRed & ~static_cast<uintptr_t>(1)); } - void setParent(Node* newParent) + void setParent(NodeType* newParent) { m_parentAndRed = reinterpret_cast<uintptr_t>(newParent) | (m_parentAndRed & 1); } - Node* left() const + NodeType* left() const { return m_left; } - void setLeft(Node* node) + void setLeft(NodeType* node) { m_left = node; } - Node* right() const + NodeType* right() const { return m_right; } - void setRight(Node* node) + void setRight(NodeType* node) { m_right = node; } @@ -155,17 +146,17 @@ public: m_parentAndRed &= ~static_cast<uintptr_t>(1); } - Node* m_left; - Node* m_right; + NodeType* m_left; + NodeType* m_right; uintptr_t m_parentAndRed; }; - + RedBlackTree() : m_root(0) { } - void insert(Node* x) + void insert(NodeType* x) { x->reset(); treeInsert(x); @@ -173,7 +164,7 @@ public: while (x != m_root && x->parent()->color() == Red) { if (x->parent() == x->parent()->parent()->left()) { - Node* y = x->parent()->parent()->right(); + NodeType* y = x->parent()->parent()->right(); if (y && y->color() == Red) { // Case 1 x->parent()->setColor(Black); @@ -193,7 +184,7 @@ public: } } else { // Same as "then" clause with "right" and "left" exchanged. - Node* y = x->parent()->parent()->left(); + NodeType* y = x->parent()->parent()->left(); if (y && y->color() == Red) { // Case 1 x->parent()->setColor(Black); @@ -217,20 +208,20 @@ public: m_root->setColor(Black); } - Node* remove(Node* z) + NodeType* remove(NodeType* z) { ASSERT(z); ASSERT(z->parent() || z == m_root); // Y is the node to be unlinked from the tree. - Node* y; + NodeType* y; if (!z->left() || !z->right()) y = z; else y = z->successor(); // Y is guaranteed to be non-null at this point. - Node* x; + NodeType* x; if (y->left()) x = y->left(); else @@ -238,7 +229,7 @@ public: // X is the child of y which might potentially replace y in // the tree. X might be null at this point. - Node* xParent; + NodeType* xParent; if (x) { x->setParent(y->parent()); xParent = x->parent(); @@ -281,20 +272,20 @@ public: return z; } - Node* remove(const KeyType& key) + NodeType* remove(const KeyType& key) { - Node* result = findExact(key); + NodeType* result = findExact(key); if (!result) return 0; return remove(result); } - Node* findExact(const KeyType& key) const + NodeType* findExact(const KeyType& key) const { - for (Node* current = m_root; current;) { - if (current->m_key == key) + for (NodeType* current = m_root; current;) { + if (current->key() == key) return current; - if (key < current->m_key) + if (key < current->key()) current = current->left(); else current = current->right(); @@ -302,13 +293,13 @@ public: return 0; } - Node* findLeastGreaterThanOrEqual(const KeyType& key) const + NodeType* findLeastGreaterThanOrEqual(const KeyType& key) const { - Node* best = 0; - for (Node* current = m_root; current;) { - if (current->m_key == key) + NodeType* best = 0; + for (NodeType* current = m_root; current;) { + if (current->key() == key) return current; - if (current->m_key < key) + if (current->key() < key) current = current->right(); else { best = current; @@ -318,13 +309,13 @@ public: return best; } - Node* findGreatestLessThanOrEqual(const KeyType& key) const + NodeType* findGreatestLessThanOrEqual(const KeyType& key) const { - Node* best = 0; - for (Node* current = m_root; current;) { - if (current->m_key == key) + NodeType* best = 0; + for (NodeType* current = m_root; current;) { + if (current->key() == key) return current; - if (current->m_key > key) + if (current->key() > key) current = current->left(); else { best = current; @@ -334,14 +325,14 @@ public: return best; } - Node* first() const + NodeType* first() const { if (!m_root) return 0; return treeMinimum(m_root); } - Node* last() const + NodeType* last() const { if (!m_root) return 0; @@ -352,7 +343,7 @@ public: size_t size() { size_t result = 0; - for (Node* current = first(); current; current = current->successor()) + for (NodeType* current = first(); current; current = current->successor()) result++; return result; } @@ -366,46 +357,46 @@ public: private: // Finds the minimum element in the sub-tree rooted at the given // node. - static Node* treeMinimum(Node* x) + static NodeType* treeMinimum(NodeType* x) { while (x->left()) x = x->left(); return x; } - static Node* treeMaximum(Node* x) + static NodeType* treeMaximum(NodeType* x) { while (x->right()) x = x->right(); return x; } - static const Node* treeMinimum(const Node* x) + static const NodeType* treeMinimum(const NodeType* x) { while (x->left()) x = x->left(); return x; } - static const Node* treeMaximum(const Node* x) + static const NodeType* treeMaximum(const NodeType* x) { while (x->right()) x = x->right(); return x; } - void treeInsert(Node* z) + void treeInsert(NodeType* z) { ASSERT(!z->left()); ASSERT(!z->right()); ASSERT(!z->parent()); ASSERT(z->color() == Red); - Node* y = 0; - Node* x = m_root; + NodeType* y = 0; + NodeType* x = m_root; while (x) { y = x; - if (z->m_key < x->m_key) + if (z->key() < x->key()) x = x->left(); else x = x->right(); @@ -414,7 +405,7 @@ private: if (!y) m_root = z; else { - if (z->m_key < y->m_key) + if (z->key() < y->key()) y->setLeft(z); else y->setRight(z); @@ -427,10 +418,10 @@ private: // Left-rotates the subtree rooted at x. // Returns the new root of the subtree (x's right child). - Node* leftRotate(Node* x) + NodeType* leftRotate(NodeType* x) { // Set y. - Node* y = x->right(); + NodeType* y = x->right(); // Turn y's left subtree into x's right subtree. x->setRight(y->left()); @@ -457,10 +448,10 @@ private: // Right-rotates the subtree rooted at y. // Returns the new root of the subtree (y's left child). - Node* rightRotate(Node* y) + NodeType* rightRotate(NodeType* y) { // Set x. - Node* x = y->left(); + NodeType* x = y->left(); // Turn x's right subtree into y's left subtree. y->setLeft(x->right()); @@ -488,7 +479,7 @@ private: // Restores the red-black property to the tree after splicing out // a node. Note that x may be null, which is why xParent must be // supplied. - void removeFixup(Node* x, Node* xParent) + void removeFixup(NodeType* x, NodeType* xParent) { while (x != m_root && (!x || x->color() == Black)) { if (x == xParent->left()) { @@ -496,7 +487,7 @@ private: // The reason is not obvious from simply looking at // the code; it comes about from the properties of the // red-black tree. - Node* w = xParent->right(); + NodeType* w = xParent->right(); ASSERT(w); // x's sibling should not be null. if (w->color() == Red) { // Case 1 @@ -536,7 +527,7 @@ private: // The reason is not obvious from simply looking at // the code; it comes about from the properties of the // red-black tree. - Node* w = xParent->left(); + NodeType* w = xParent->left(); ASSERT(w); // x's sibling should not be null. if (w->color() == Red) { // Case 1 @@ -574,7 +565,7 @@ private: x->setColor(Black); } - Node* m_root; + NodeType* m_root; }; } diff --git a/Source/JavaScriptCore/wtf/RefCountedLeakCounter.h b/Source/JavaScriptCore/wtf/RefCountedLeakCounter.h index 22c7506ac..476b1735a 100644 --- a/Source/JavaScriptCore/wtf/RefCountedLeakCounter.h +++ b/Source/JavaScriptCore/wtf/RefCountedLeakCounter.h @@ -27,14 +27,14 @@ namespace WTF { struct RefCountedLeakCounter { - static void suppressMessages(const char*); - static void cancelMessageSuppression(const char*); + WTF_EXPORT_PRIVATE static void suppressMessages(const char*); + WTF_EXPORT_PRIVATE static void cancelMessageSuppression(const char*); - explicit RefCountedLeakCounter(const char* description); - ~RefCountedLeakCounter(); + WTF_EXPORT_PRIVATE explicit RefCountedLeakCounter(const char* description); + WTF_EXPORT_PRIVATE ~RefCountedLeakCounter(); - void increment(); - void decrement(); + WTF_EXPORT_PRIVATE void increment(); + WTF_EXPORT_PRIVATE void decrement(); #ifndef NDEBUG private: diff --git a/Source/JavaScriptCore/wtf/SHA1.h b/Source/JavaScriptCore/wtf/SHA1.h index dad6dc867..e8cc802e9 100644 --- a/Source/JavaScriptCore/wtf/SHA1.h +++ b/Source/JavaScriptCore/wtf/SHA1.h @@ -37,16 +37,16 @@ namespace WTF { class SHA1 { public: - SHA1(); + WTF_EXPORT_PRIVATE SHA1(); void addBytes(const Vector<uint8_t>& input) { addBytes(input.data(), input.size()); } - void addBytes(const uint8_t* input, size_t length); + WTF_EXPORT_PRIVATE void addBytes(const uint8_t* input, size_t length); // computeHash has a side effect of resetting the state of the object. - void computeHash(Vector<uint8_t, 20>&); + WTF_EXPORT_PRIVATE void computeHash(Vector<uint8_t, 20>&); private: void finalize(); diff --git a/Source/JavaScriptCore/wtf/StdLibExtras.h b/Source/JavaScriptCore/wtf/StdLibExtras.h index 3f99c4d3f..e4d7c8fc0 100644 --- a/Source/JavaScriptCore/wtf/StdLibExtras.h +++ b/Source/JavaScriptCore/wtf/StdLibExtras.h @@ -107,6 +107,13 @@ TypePtr reinterpret_cast_ptr(const void* ptr) namespace WTF { +static const size_t KB = 1024; + +inline bool isPointerAligned(void* p) +{ + return !((intptr_t)(p) & (sizeof(char*) - 1)); +} + /* * C++'s idea of a reinterpret_cast lacks sufficient cojones. */ @@ -283,6 +290,8 @@ inline void* operator new(size_t, NotNullTag, void* location) return location; } +using WTF::KB; +using WTF::isPointerAligned; using WTF::binarySearch; using WTF::bitwise_cast; using WTF::safeCast; diff --git a/Source/JavaScriptCore/wtf/Threading.cpp b/Source/JavaScriptCore/wtf/Threading.cpp index f2e0565e9..d8dbbae4f 100644 --- a/Source/JavaScriptCore/wtf/Threading.cpp +++ b/Source/JavaScriptCore/wtf/Threading.cpp @@ -89,7 +89,7 @@ ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char* // This function is deprecated but needs to be kept around for backward // compatibility. Use the 3-argument version of createThread above. -ThreadIdentifier createThread(ThreadFunction entryPoint, void* data); +WTF_EXPORT_PRIVATE ThreadIdentifier createThread(ThreadFunction entryPoint, void* data); ThreadIdentifier createThread(ThreadFunction entryPoint, void* data) { diff --git a/Source/JavaScriptCore/wtf/Threading.h b/Source/JavaScriptCore/wtf/Threading.h index 3a89757a9..1dee5da1c 100644 --- a/Source/JavaScriptCore/wtf/Threading.h +++ b/Source/JavaScriptCore/wtf/Threading.h @@ -83,11 +83,11 @@ typedef void* (*ThreadFunction)(void* argument); // This function must be called from the main thread. It is safe to call it repeatedly. // Darwin is an exception to this rule: it is OK to call it from any thread, the only // requirement is that the calls are not reentrant. -void initializeThreading(); +WTF_EXPORT_PRIVATE void initializeThreading(); // Returns 0 if thread creation failed. // The thread name must be a literal since on some platforms it's passed in to the thread. -ThreadIdentifier createThread(ThreadFunction, void*, const char* threadName); +WTF_EXPORT_PRIVATE ThreadIdentifier createThread(ThreadFunction, void*, const char* threadName); // Internal platform-specific createThread implementation. ThreadIdentifier createThreadInternal(ThreadFunction, void*, const char* threadName); @@ -96,14 +96,14 @@ ThreadIdentifier createThreadInternal(ThreadFunction, void*, const char* threadN // Helpful for platforms where the thread name must be set from within the thread. void initializeCurrentThreadInternal(const char* threadName); -ThreadIdentifier currentThread(); -int waitForThreadCompletion(ThreadIdentifier, void**); -void detachThread(ThreadIdentifier); +WTF_EXPORT_PRIVATE ThreadIdentifier currentThread(); +WTF_EXPORT_PRIVATE int waitForThreadCompletion(ThreadIdentifier, void**); +WTF_EXPORT_PRIVATE void detachThread(ThreadIdentifier); -void yield(); +WTF_EXPORT_PRIVATE void yield(); -void lockAtomicallyInitializedStaticMutex(); -void unlockAtomicallyInitializedStaticMutex(); +WTF_EXPORT_PRIVATE void lockAtomicallyInitializedStaticMutex(); +WTF_EXPORT_PRIVATE void unlockAtomicallyInitializedStaticMutex(); } // namespace WTF diff --git a/Source/JavaScriptCore/wtf/ThreadingPrimitives.h b/Source/JavaScriptCore/wtf/ThreadingPrimitives.h index 1bed5d3ae..2ac42c8f1 100644 --- a/Source/JavaScriptCore/wtf/ThreadingPrimitives.h +++ b/Source/JavaScriptCore/wtf/ThreadingPrimitives.h @@ -82,12 +82,12 @@ typedef void* PlatformCondition; class Mutex { WTF_MAKE_NONCOPYABLE(Mutex); WTF_MAKE_FAST_ALLOCATED; public: - Mutex(); - ~Mutex(); + WTF_EXPORT_PRIVATE Mutex(); + WTF_EXPORT_PRIVATE ~Mutex(); - void lock(); - bool tryLock(); - void unlock(); + WTF_EXPORT_PRIVATE void lock(); + WTF_EXPORT_PRIVATE bool tryLock(); + WTF_EXPORT_PRIVATE void unlock(); public: PlatformMutex& impl() { return m_mutex; } @@ -118,15 +118,15 @@ private: class ThreadCondition { WTF_MAKE_NONCOPYABLE(ThreadCondition); public: - ThreadCondition(); - ~ThreadCondition(); + WTF_EXPORT_PRIVATE ThreadCondition(); + WTF_EXPORT_PRIVATE ~ThreadCondition(); - void wait(Mutex& mutex); + WTF_EXPORT_PRIVATE void wait(Mutex& mutex); // Returns true if the condition was signaled before absoluteTime, false if the absoluteTime was reached or is in the past. // The absoluteTime is in seconds, starting on January 1, 1970. The time is assumed to use the same time zone as WTF::currentTime(). - bool timedWait(Mutex&, double absoluteTime); - void signal(); - void broadcast(); + WTF_EXPORT_PRIVATE bool timedWait(Mutex&, double absoluteTime); + WTF_EXPORT_PRIVATE void signal(); + WTF_EXPORT_PRIVATE void broadcast(); private: PlatformCondition m_condition; diff --git a/Source/JavaScriptCore/wtf/Uint8Array.h b/Source/JavaScriptCore/wtf/Uint8Array.h index 58fdb842b..a0959706c 100644 --- a/Source/JavaScriptCore/wtf/Uint8Array.h +++ b/Source/JavaScriptCore/wtf/Uint8Array.h @@ -46,7 +46,7 @@ public: inline PassRefPtr<Uint8Array> subarray(int start) const; inline PassRefPtr<Uint8Array> subarray(int start, int end) const; -private: +protected: inline Uint8Array(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length); diff --git a/Source/JavaScriptCore/wtf/Uint8ClampedArray.h b/Source/JavaScriptCore/wtf/Uint8ClampedArray.h new file mode 100644 index 000000000..f1044091b --- /dev/null +++ b/Source/JavaScriptCore/wtf/Uint8ClampedArray.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). + * + * 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Uint8ClampedArray_h +#define Uint8ClampedArray_h + +#include "Uint8Array.h" + +namespace WTF { + +class Uint8ClampedArray : public Uint8Array { +public: + static inline PassRefPtr<Uint8ClampedArray> create(unsigned length); + static inline PassRefPtr<Uint8ClampedArray> create(unsigned char* array, unsigned length); + static inline PassRefPtr<Uint8ClampedArray> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length); + + // Can’t use "using" here due to a bug in the RVCT compiler. + bool set(TypedArrayBase<unsigned char>* array, unsigned offset) { return TypedArrayBase<unsigned char>::set(array, offset); } + inline void set(unsigned index, double value); + + inline PassRefPtr<Uint8ClampedArray> subarray(int start) const; + inline PassRefPtr<Uint8ClampedArray> subarray(int start, int end) const; + +private: + inline Uint8ClampedArray(PassRefPtr<ArrayBuffer>, + unsigned byteOffset, + unsigned length); + // Make constructor visible to superclass. + friend class TypedArrayBase<unsigned char>; + + // Overridden from ArrayBufferView. + virtual bool isUnsignedByteClampedArray() const { return true; } +}; + +PassRefPtr<Uint8ClampedArray> Uint8ClampedArray::create(unsigned length) +{ + return TypedArrayBase<unsigned char>::create<Uint8ClampedArray>(length); +} + +PassRefPtr<Uint8ClampedArray> Uint8ClampedArray::create(unsigned char* array, unsigned length) +{ + return TypedArrayBase<unsigned char>::create<Uint8ClampedArray>(array, length); +} + +PassRefPtr<Uint8ClampedArray> Uint8ClampedArray::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length) +{ + return TypedArrayBase<unsigned char>::create<Uint8ClampedArray>(buffer, byteOffset, length); +} + +void Uint8ClampedArray::set(unsigned index, double value) +{ + if (index >= m_length) + return; + if (isnan(value) || value < 0) + value = 0; + else if (value > 255) + value = 255; + data()[index] = static_cast<unsigned char>(value + 0.5); +} + +Uint8ClampedArray::Uint8ClampedArray(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length) +: Uint8Array(buffer, byteOffset, length) +{ +} + +PassRefPtr<Uint8ClampedArray> Uint8ClampedArray::subarray(int start) const +{ + return subarray(start, length()); +} + +PassRefPtr<Uint8ClampedArray> Uint8ClampedArray::subarray(int start, int end) const +{ + return subarrayImpl<Uint8ClampedArray>(start, end); +} + +} // namespace WTF + +using WTF::Uint8ClampedArray; + +#endif // Uint8ClampedArray_h diff --git a/Source/JavaScriptCore/wtf/Vector.h b/Source/JavaScriptCore/wtf/Vector.h index 1368ac99b..175f1a582 100644 --- a/Source/JavaScriptCore/wtf/Vector.h +++ b/Source/JavaScriptCore/wtf/Vector.h @@ -194,7 +194,7 @@ namespace WTF { static bool compare(const T* a, const T* b, size_t size) { for (size_t i = 0; i < size; ++i) - if (a[i] != b[i]) + if (!(a[i] == b[i])) return false; return true; } diff --git a/Source/JavaScriptCore/wtf/WTFThreadData.h b/Source/JavaScriptCore/wtf/WTFThreadData.h index 81b817f6f..b02d10d7c 100644 --- a/Source/JavaScriptCore/wtf/WTFThreadData.h +++ b/Source/JavaScriptCore/wtf/WTFThreadData.h @@ -78,8 +78,8 @@ typedef void (*AtomicStringTableDestructor)(AtomicStringTable*); class WTFThreadData { WTF_MAKE_NONCOPYABLE(WTFThreadData); public: - WTFThreadData(); - ~WTFThreadData(); + WTF_EXPORT_PRIVATE WTFThreadData(); + WTF_EXPORT_PRIVATE ~WTFThreadData(); AtomicStringTable* atomicStringTable() { diff --git a/Source/JavaScriptCore/wtf/dtoa.h b/Source/JavaScriptCore/wtf/dtoa.h index df33e2cdc..d27c59206 100644 --- a/Source/JavaScriptCore/wtf/dtoa.h +++ b/Source/JavaScriptCore/wtf/dtoa.h @@ -31,19 +31,19 @@ extern WTF::Mutex* s_dtoaP5Mutex; typedef char DtoaBuffer[80]; -void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision); -void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision); -void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision); +WTF_EXPORT_PRIVATE void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision); +WTF_EXPORT_PRIVATE void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision); +WTF_EXPORT_PRIVATE void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision); // s00: input string. Must not be 0 and must be terminated by 0. // se: *se will have the last consumed character position + 1. -double strtod(const char* s00, char** se); +WTF_EXPORT_PRIVATE double strtod(const char* s00, char** se); // Size = 80 for sizeof(DtoaBuffer) + some sign bits, decimal point, 'e', exponent digits. const unsigned NumberToStringBufferLength = 96; typedef char NumberToStringBuffer[NumberToStringBufferLength]; typedef UChar NumberToUStringBuffer[NumberToStringBufferLength]; -const char* numberToString(double, NumberToStringBuffer); +WTF_EXPORT_PRIVATE const char* numberToString(double, NumberToStringBuffer); const char* numberToFixedPrecisionString(double, unsigned significantFigures, NumberToStringBuffer, bool truncateTrailingZeros = false); const char* numberToFixedWidthString(double, unsigned decimalPlaces, NumberToStringBuffer); diff --git a/Source/JavaScriptCore/wtf/efl/OwnPtrEfl.cpp b/Source/JavaScriptCore/wtf/efl/OwnPtrEfl.cpp index 7ec517029..3f3ad6420 100644 --- a/Source/JavaScriptCore/wtf/efl/OwnPtrEfl.cpp +++ b/Source/JavaScriptCore/wtf/efl/OwnPtrEfl.cpp @@ -29,6 +29,7 @@ #include <Ecore.h> #include <Ecore_Evas.h> +#include <Eina.h> #include <Evas.h> namespace WTF { @@ -50,4 +51,10 @@ void deleteOwnedPtr(Ecore_Pipe* ptr) ecore_pipe_del(ptr); } +void deleteOwnedPtr(Eina_Module* ptr) +{ + if (ptr) + eina_module_free(ptr); // If module wasn't unloaded, eina_module_free() calls eina_module_unload(). +} + } diff --git a/Source/JavaScriptCore/wtf/gobject/GOwnPtr.cpp b/Source/JavaScriptCore/wtf/gobject/GOwnPtr.cpp index 50c7b9ffc..c727956ce 100644 --- a/Source/JavaScriptCore/wtf/gobject/GOwnPtr.cpp +++ b/Source/JavaScriptCore/wtf/gobject/GOwnPtr.cpp @@ -49,6 +49,18 @@ template <> void freeOwnedGPtr<GDir>(GDir* ptr) g_dir_close(ptr); } +template <> void freeOwnedGPtr<GTimer>(GTimer* ptr) +{ + if (ptr) + g_timer_destroy(ptr); +} + +template <> void freeOwnedGPtr<GKeyFile>(GKeyFile* ptr) +{ + if (ptr) + g_key_file_free(ptr); +} + } // namespace WTF #endif // ENABLE(GLIB_SUPPORT) diff --git a/Source/JavaScriptCore/wtf/gobject/GOwnPtr.h b/Source/JavaScriptCore/wtf/gobject/GOwnPtr.h index 9ff85c5a4..221971f97 100644 --- a/Source/JavaScriptCore/wtf/gobject/GOwnPtr.h +++ b/Source/JavaScriptCore/wtf/gobject/GOwnPtr.h @@ -37,6 +37,8 @@ template<> void freeOwnedGPtr<GError>(GError*); template<> void freeOwnedGPtr<GList>(GList*); template<> void freeOwnedGPtr<GPatternSpec>(GPatternSpec*); template<> void freeOwnedGPtr<GDir>(GDir*); +template<> void freeOwnedGPtr<GTimer>(GTimer*); +template<> void freeOwnedGPtr<GKeyFile>(GKeyFile*); template <typename T> class GOwnPtr { WTF_MAKE_NONCOPYABLE(GOwnPtr); diff --git a/Source/JavaScriptCore/wtf/gobject/GTypedefs.h b/Source/JavaScriptCore/wtf/gobject/GTypedefs.h index 66cedd6d2..e2b2ba6b8 100644 --- a/Source/JavaScriptCore/wtf/gobject/GTypedefs.h +++ b/Source/JavaScriptCore/wtf/gobject/GTypedefs.h @@ -58,6 +58,8 @@ typedef struct _GSocketConnection GSocketConnection; typedef struct _GSource GSource; typedef struct _GVariant GVariant; typedef union _GdkEvent GdkEvent; +typedef struct _GTimer GTimer; +typedef struct _GKeyFile GKeyFile; #if USE(CAIRO) typedef struct _cairo_surface cairo_surface_t; diff --git a/Source/JavaScriptCore/wtf/text/AtomicString.cpp b/Source/JavaScriptCore/wtf/text/AtomicString.cpp index 966879827..d775e7bb9 100644 --- a/Source/JavaScriptCore/wtf/text/AtomicString.cpp +++ b/Source/JavaScriptCore/wtf/text/AtomicString.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> + * Copyright (C) 2012 Google Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -250,11 +251,52 @@ PassRefPtr<StringImpl> AtomicString::add(const UChar* s) return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer); } -PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* r) +struct SubstringLocation { + StringImpl* baseString; + unsigned start; + unsigned length; +}; + +struct SubstringTranslator { + static unsigned hash(const SubstringLocation& buffer) + { + return StringHasher::computeHash(buffer.baseString->characters() + buffer.start, buffer.length); + } + + static bool equal(StringImpl* const& string, const SubstringLocation& buffer) + { + return WTF::equal(string, buffer.baseString->characters() + buffer.start, buffer.length); + } + + static void translate(StringImpl*& location, const SubstringLocation& buffer, unsigned hash) + { + location = StringImpl::create(buffer.baseString, buffer.start, buffer.length).leakRef(); + location->setHash(hash); + location->setIsAtomic(true); + } +}; + +PassRefPtr<StringImpl> AtomicString::add(StringImpl* baseString, unsigned start, unsigned length) { - if (!r || r->isAtomic()) - return r; + if (!baseString) + return 0; + + if (!length || start >= baseString->length()) + return StringImpl::empty(); + unsigned maxLength = baseString->length() - start; + if (length >= maxLength) { + if (!start) + return add(baseString); + length = maxLength; + } + + SubstringLocation buffer = { baseString, start, length }; + return addToStringTable<SubstringLocation, SubstringTranslator>(buffer); +} + +PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* r) +{ if (!r->length()) return StringImpl::empty(); diff --git a/Source/JavaScriptCore/wtf/text/AtomicString.h b/Source/JavaScriptCore/wtf/text/AtomicString.h index 43b38d179..b135845fe 100644 --- a/Source/JavaScriptCore/wtf/text/AtomicString.h +++ b/Source/JavaScriptCore/wtf/text/AtomicString.h @@ -38,7 +38,7 @@ struct AtomicStringHash; class AtomicString { public: - static void init(); + WTF_EXPORT_PRIVATE static void init(); AtomicString() { } AtomicString(const LChar* s) : m_string(add(s)) { } @@ -49,12 +49,13 @@ public: ATOMICSTRING_CONVERSION AtomicString(StringImpl* imp) : m_string(add(imp)) { } AtomicString(AtomicStringImpl* imp) : m_string(imp) { } ATOMICSTRING_CONVERSION AtomicString(const String& s) : m_string(add(s.impl())) { } + AtomicString(StringImpl* baseString, unsigned start, unsigned length) : m_string(add(baseString, start, length)) { } // Hash table deleted values, which are only constructed and never copied or destroyed. AtomicString(WTF::HashTableDeletedValueType) : m_string(WTF::HashTableDeletedValue) { } bool isHashTableDeletedValue() const { return m_string.isHashTableDeletedValue(); } - static AtomicStringImpl* find(const UChar* s, unsigned length, unsigned existingHash); + WTF_EXPORT_PRIVATE static AtomicStringImpl* find(const UChar* s, unsigned length, unsigned existingHash); operator const String&() const { return m_string; } const String& string() const { return m_string; }; @@ -83,7 +84,7 @@ public: bool endsWith(const String& s, bool caseSensitive = true) const { return m_string.endsWith(s, caseSensitive); } - AtomicString lower() const; + WTF_EXPORT_PRIVATE AtomicString lower() const; AtomicString upper() const { return AtomicString(impl()->upper()); } int toInt(bool* ok = 0) const { return m_string.toInt(ok); } @@ -120,20 +121,21 @@ public: private: String m_string; - static PassRefPtr<StringImpl> add(const LChar*); + WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(const LChar*); ALWAYS_INLINE static PassRefPtr<StringImpl> add(const char* s) { return add(reinterpret_cast<const LChar*>(s)); }; - static PassRefPtr<StringImpl> add(const UChar*, unsigned length); + WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(const UChar*, unsigned length); ALWAYS_INLINE static PassRefPtr<StringImpl> add(const char* s, unsigned length) { return add(reinterpret_cast<const char*>(s), length); }; - static PassRefPtr<StringImpl> add(const UChar*, unsigned length, unsigned existingHash); - static PassRefPtr<StringImpl> add(const UChar*); - ALWAYS_INLINE PassRefPtr<StringImpl> add(StringImpl* r) + WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(const UChar*, unsigned length, unsigned existingHash); + WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(const UChar*); + WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(StringImpl*, unsigned offset, unsigned length); + ALWAYS_INLINE static PassRefPtr<StringImpl> add(StringImpl* r) { if (!r || r->isAtomic()) return r; return addSlowCase(r); } - static PassRefPtr<StringImpl> addSlowCase(StringImpl*); - static AtomicString fromUTF8Internal(const char*, const char*); + WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(StringImpl*); + WTF_EXPORT_PRIVATE static AtomicString fromUTF8Internal(const char*, const char*); }; inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); } diff --git a/Source/JavaScriptCore/wtf/text/CString.h b/Source/JavaScriptCore/wtf/text/CString.h index 343a7a525..d43ad4bd7 100644 --- a/Source/JavaScriptCore/wtf/text/CString.h +++ b/Source/JavaScriptCore/wtf/text/CString.h @@ -52,16 +52,16 @@ private: class CString { public: CString() { } - CString(const char*); - CString(const char*, size_t length); + WTF_EXPORT_PRIVATE CString(const char*); + WTF_EXPORT_PRIVATE CString(const char*, size_t length); CString(CStringBuffer* buffer) : m_buffer(buffer) { } - static CString newUninitialized(size_t length, char*& characterBuffer); + WTF_EXPORT_PRIVATE static CString newUninitialized(size_t length, char*& characterBuffer); const char* data() const { return m_buffer ? m_buffer->data() : 0; } - char* mutableData(); + WTF_EXPORT_PRIVATE char* mutableData(); size_t length() const { return m_buffer ? m_buffer->length() - 1 : 0; @@ -77,7 +77,7 @@ private: RefPtr<CStringBuffer> m_buffer; }; -bool operator==(const CString& a, const CString& b); +WTF_EXPORT_PRIVATE bool operator==(const CString& a, const CString& b); inline bool operator!=(const CString& a, const CString& b) { return !(a == b); } } // namespace WTF diff --git a/Source/JavaScriptCore/wtf/text/StringBuilder.cpp b/Source/JavaScriptCore/wtf/text/StringBuilder.cpp index 6d3c310e6..4eac75649 100644 --- a/Source/JavaScriptCore/wtf/text/StringBuilder.cpp +++ b/Source/JavaScriptCore/wtf/text/StringBuilder.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,7 +33,7 @@ namespace WTF { static const unsigned minimumCapacity = 16; -void StringBuilder::reifyString() +void StringBuilder::reifyString() const { // Check if the string already exists. if (!m_string.isNull()) { @@ -68,6 +69,7 @@ void StringBuilder::resize(unsigned newSize) // If there is a buffer, we only need to duplicate it if it has more than one ref. if (m_buffer) { + m_string = String(); // Clear the string to remove the reference to m_buffer if any before checking the reference count of m_buffer. if (!m_buffer->hasOneRef()) { if (m_buffer->is8Bit()) allocateBuffer(m_buffer->characters8(), m_buffer->length()); @@ -75,7 +77,6 @@ void StringBuilder::resize(unsigned newSize) allocateBuffer(m_buffer->characters16(), m_buffer->length()); } m_length = newSize; - m_string = String(); return; } @@ -285,10 +286,15 @@ void StringBuilder::append(const LChar* characters, unsigned length) } } +bool StringBuilder::canShrink() const +{ + // Only shrink the buffer if it's less than 80% full. Need to tune this heuristic! + return m_buffer && m_buffer->length() > (m_length + (m_length >> 2)); +} + void StringBuilder::shrinkToFit() { - // If the buffer is at least 80% full, don't bother copying. Need to tune this heuristic! - if (m_buffer && m_buffer->length() > (m_length + (m_length >> 2))) { + if (canShrink()) { if (m_is8Bit) reallocateBuffer<LChar>(m_length); else diff --git a/Source/JavaScriptCore/wtf/text/StringBuilder.h b/Source/JavaScriptCore/wtf/text/StringBuilder.h index da1e8320d..d896d17b1 100644 --- a/Source/JavaScriptCore/wtf/text/StringBuilder.h +++ b/Source/JavaScriptCore/wtf/text/StringBuilder.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,12 +27,15 @@ #ifndef StringBuilder_h #define StringBuilder_h -#include <wtf/Vector.h> +#include <wtf/text/AtomicString.h> #include <wtf/text/WTFString.h> namespace WTF { class StringBuilder { + // Disallow copying since it's expensive and we don't want code to do it by accident. + WTF_MAKE_NONCOPYABLE(StringBuilder); + public: StringBuilder() : m_length(0) @@ -41,8 +45,8 @@ public: { } - void append(const UChar*, unsigned); - void append(const LChar*, unsigned); + WTF_EXPORT_PRIVATE void append(const UChar*, unsigned); + WTF_EXPORT_PRIVATE void append(const LChar*, unsigned); ALWAYS_INLINE void append(const char* characters, unsigned length) { append(reinterpret_cast<const LChar*>(characters), length); } @@ -51,9 +55,8 @@ public: if (!string.length()) return; - // If we're appending to an empty string, and there is not buffer - // (in case reserveCapacity has been called) then just retain the - // string. + // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called) + // then just retain the string. if (!m_length && !m_buffer) { m_string = string; m_length = string.length(); @@ -67,6 +70,36 @@ public: append(string.characters16(), string.length()); } + void append(const StringBuilder& other) + { + if (!other.m_length) + return; + + // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called) + // then just retain the string. + if (!m_length && !m_buffer && !other.m_string.isNull()) { + m_string = other.m_string; + m_length = other.m_length; + return; + } + + append(other.characters(), other.m_length); + } + + void append(const String& string, unsigned offset, unsigned length) + { + if (!string.length()) + return; + + if ((offset + length) > string.length()) + return; + + if (string.is8Bit()) + append(string.characters8() + offset, length); + else + append(string.characters16() + offset, length); + } + void append(const char* characters) { if (characters) @@ -94,44 +127,59 @@ public: void append(char c) { - if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) { - if (m_is8Bit) - m_bufferCharacters8[m_length++] = (LChar)c; - else - m_bufferCharacters16[m_length++] = (LChar)c; - } - else - append(&c, 1); + append(static_cast<LChar>(c)); } String toString() { - if (m_string.isNull()) { - shrinkToFit(); + shrinkToFit(); + if (m_string.isNull()) reifyString(); - } return m_string; } - String toStringPreserveCapacity() + const String& toStringPreserveCapacity() const { if (m_string.isNull()) reifyString(); return m_string; } + AtomicString toAtomicString() const + { + if (!m_length) + return AtomicString(); + + // If the buffer is sufficiently over-allocated, make a new AtomicString from a copy so its buffer is not so large. + if (canShrink()) + return AtomicString(characters(), length()); + + if (!m_string.isNull()) + return AtomicString(m_string); + + ASSERT(m_buffer); + return AtomicString(m_buffer.get(), 0, m_length); + } + unsigned length() const { return m_length; } - bool isEmpty() const { return !length(); } + bool isEmpty() const { return !m_length; } - void reserveCapacity(unsigned newCapacity); + WTF_EXPORT_PRIVATE void reserveCapacity(unsigned newCapacity); - void resize(unsigned newSize); + unsigned capacity() const + { + return m_buffer ? m_buffer->length() : m_length; + } + + WTF_EXPORT_PRIVATE void resize(unsigned newSize); + + WTF_EXPORT_PRIVATE bool canShrink() const; - void shrinkToFit(); + WTF_EXPORT_PRIVATE void shrinkToFit(); UChar operator[](unsigned i) const { @@ -178,6 +226,8 @@ public: return m_buffer->characters(); } + bool is8Bit() const { return m_is8Bit; } + void clear() { m_length = 0; @@ -188,6 +238,16 @@ public: m_valid16BitShadowLength = 0; } + void swap(StringBuilder& stringBuilder) + { + std::swap(m_length, stringBuilder.m_length); + m_string.swap(stringBuilder.m_string); + m_buffer.swap(stringBuilder.m_buffer); + std::swap(m_is8Bit, stringBuilder.m_is8Bit); + std::swap(m_valid16BitShadowLength, stringBuilder.m_valid16BitShadowLength); + std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8); + } + private: void allocateBuffer(const LChar* currentCharacters, unsigned requiredLength); void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength); @@ -200,10 +260,10 @@ private: CharType* appendUninitializedSlow(unsigned length); template <typename CharType> ALWAYS_INLINE CharType * getBufferCharacters(); - void reifyString(); + WTF_EXPORT_PRIVATE void reifyString() const; unsigned m_length; - String m_string; + mutable String m_string; RefPtr<StringImpl> m_buffer; bool m_is8Bit; mutable unsigned m_valid16BitShadowLength; @@ -227,6 +287,45 @@ ALWAYS_INLINE UChar* StringBuilder::getBufferCharacters<UChar>() return m_bufferCharacters16; } +template <typename CharType> +bool equal(const StringBuilder& s, const CharType* buffer, unsigned length) +{ + if (s.length() != length) + return false; + + if (s.is8Bit()) + return equal(s.characters8(), buffer, length); + + return equal(s.characters16(), buffer, length); +} + +template <typename StringType> +bool equal(const StringBuilder& a, const StringType& b) +{ + if (a.length() != b.length()) + return false; + + if (!a.length()) + return true; + + if (a.is8Bit()) { + if (b.is8Bit()) + return equal(a.characters8(), b.characters8(), a.length()); + return equal(a.characters8(), b.characters16(), a.length()); + } + + if (b.is8Bit()) + return equal(a.characters16(), b.characters8(), a.length()); + return equal(a.characters16(), b.characters16(), a.length()); +} + +inline bool operator==(const StringBuilder& a, const StringBuilder& b) { return equal(a, b); } +inline bool operator!=(const StringBuilder& a, const StringBuilder& b) { return !equal(a, b); } +inline bool operator==(const StringBuilder& a, const String& b) { return equal(a, b); } +inline bool operator!=(const StringBuilder& a, const String& b) { return !equal(a, b); } +inline bool operator==(const String& a, const StringBuilder& b) { return equal(b, a); } +inline bool operator!=(const String& a, const StringBuilder& b) { return !equal(b, a); } + } // namespace WTF using WTF::StringBuilder; diff --git a/Source/JavaScriptCore/wtf/text/StringHash.h b/Source/JavaScriptCore/wtf/text/StringHash.h index cde591c18..1b7a2ee2c 100644 --- a/Source/JavaScriptCore/wtf/text/StringHash.h +++ b/Source/JavaScriptCore/wtf/text/StringHash.h @@ -100,7 +100,9 @@ namespace WTF { static unsigned hash(StringImpl* str) { - return hash(str->characters(), str->length()); + if (str->is8Bit()) + return hash(str->characters8(), str->length()); + return hash(str->characters16(), str->length()); } static unsigned hash(const LChar* data, unsigned length) diff --git a/Source/JavaScriptCore/wtf/text/StringImpl.cpp b/Source/JavaScriptCore/wtf/text/StringImpl.cpp index aa5a8d56e..3f73556b5 100644 --- a/Source/JavaScriptCore/wtf/text/StringImpl.cpp +++ b/Source/JavaScriptCore/wtf/text/StringImpl.cpp @@ -30,6 +30,8 @@ #include "StringHash.h" #include <wtf/StdLibExtras.h> #include <wtf/WTFThreadData.h> +#include <wtf/unicode/CharacterNames.h> + using namespace std; @@ -378,19 +380,53 @@ PassRefPtr<StringImpl> StringImpl::upper() return newImpl.release(); // Do a slower implementation for cases that include non-ASCII Latin-1 characters. - for (int32_t i = 0; i < length; i++) - data8[i] = static_cast<LChar>(Unicode::toUpper(m_data8[i])); + int numberSharpSCharacters = 0; + + // There are two special cases. + // 1. latin-1 characters when converted to upper case are 16 bit characters. + // 2. Lower case sharp-S converts to "SS" (two characters) + for (int32_t i = 0; i < length; i++) { + LChar c = m_data8[i]; + if (UNLIKELY(c == smallLetterSharpS)) + numberSharpSCharacters++; + UChar upper = Unicode::toUpper(c); + if (UNLIKELY(upper > 0xff)) { + // Since this upper-cased character does not fit in an 8-bit string, we need to take the 16-bit path. + goto upconvert; + } + data8[i] = static_cast<LChar>(upper); + } + + if (!numberSharpSCharacters) + return newImpl.release(); + + // We have numberSSCharacters sharp-s characters, but none of the other special characters. + newImpl = createUninitialized(m_length + numberSharpSCharacters, data8); + + LChar* dest = data8; + + for (int32_t i = 0; i < length; i++) { + LChar c = m_data8[i]; + if (c == smallLetterSharpS) { + *dest++ = 'S'; + *dest++ = 'S'; + } else + *dest++ = static_cast<LChar>(Unicode::toUpper(c)); + } return newImpl.release(); } +upconvert: + const UChar* source16 = characters(); + UChar* data16; RefPtr<StringImpl> newImpl = createUninitialized(m_length, data16); // Do a faster loop for the case where all the characters are ASCII. UChar ored = 0; for (int i = 0; i < length; i++) { - UChar c = m_data16[i]; + UChar c = source16[i]; ored |= c; data16[i] = toASCIIUpper(c); } @@ -400,11 +436,11 @@ PassRefPtr<StringImpl> StringImpl::upper() // Do a slower implementation for cases that include non-ASCII characters. bool error; newImpl = createUninitialized(m_length, data16); - int32_t realLength = Unicode::toUpper(data16, length, m_data16, m_length, &error); + int32_t realLength = Unicode::toUpper(data16, length, source16, m_length, &error); if (!error && realLength == length) return newImpl; newImpl = createUninitialized(realLength, data16); - Unicode::toUpper(data16, realLength, m_data16, m_length, &error); + Unicode::toUpper(data16, realLength, source16, m_length, &error); if (error) return this; return newImpl.release(); @@ -715,6 +751,16 @@ float StringImpl::toFloat(bool* ok, bool* didReadNumber) return charactersToFloat(characters16(), m_length, ok, didReadNumber); } +bool equalIgnoringCase(const LChar* a, const LChar* b, unsigned length) +{ + while (length--) { + LChar bc = *b++; + if (foldCase(*a++) != foldCase(bc)) + return false; + } + return true; +} + bool equalIgnoringCase(const UChar* a, const LChar* b, unsigned length) { while (length--) { @@ -849,6 +895,35 @@ size_t StringImpl::findIgnoringCase(const LChar* matchString, unsigned index) return index + i; } +template <typename CharType> +ALWAYS_INLINE static size_t findInner(const CharType* searchCharacters, const CharType* matchCharacters, unsigned index, unsigned searchLength, unsigned matchLength) +{ + // Optimization: keep a running hash of the strings, + // only call memcmp if the hashes match. + + // delta is the number of additional times to test; delta == 0 means test only once. + unsigned delta = searchLength - matchLength; + + unsigned searchHash = 0; + unsigned matchHash = 0; + + for (unsigned i = 0; i < matchLength; ++i) { + searchHash += searchCharacters[i]; + matchHash += matchCharacters[i]; + } + + unsigned i = 0; + // keep looping until we match + while (searchHash != matchHash || memcmp(searchCharacters + i, matchCharacters, matchLength * sizeof(CharType))) { + if (i == delta) + return notFound; + searchHash += searchCharacters[i + matchLength]; + searchHash -= searchCharacters[i]; + ++i; + } + return index + i; +} + size_t StringImpl::find(StringImpl* matchString, unsigned index) { // Check for null or empty string to match against @@ -871,31 +946,12 @@ size_t StringImpl::find(StringImpl* matchString, unsigned index) unsigned searchLength = length() - index; if (matchLength > searchLength) return notFound; - // delta is the number of additional times to test; delta == 0 means test only once. - unsigned delta = searchLength - matchLength; - const UChar* searchCharacters = characters() + index; - const UChar* matchCharacters = matchString->characters(); + if (is8Bit() && matchString->is8Bit()) + return findInner(characters8() + index, matchString->characters8(), index, searchLength, matchLength); - // Optimization 2: keep a running hash of the strings, - // only call memcmp if the hashes match. - unsigned searchHash = 0; - unsigned matchHash = 0; - for (unsigned i = 0; i < matchLength; ++i) { - searchHash += searchCharacters[i]; - matchHash += matchCharacters[i]; - } + return findInner(characters() + index, matchString->characters(), index, searchLength, matchLength); - unsigned i = 0; - // keep looping until we match - while (searchHash != matchHash || memcmp(searchCharacters + i, matchCharacters, matchLength * sizeof(UChar))) { - if (i == delta) - return notFound; - searchHash += searchCharacters[i + matchLength]; - searchHash -= searchCharacters[i]; - ++i; - } - return index + i; } size_t StringImpl::findIgnoringCase(StringImpl* matchString, unsigned index) @@ -936,33 +992,15 @@ size_t StringImpl::reverseFind(UChar c, unsigned index) return WTF::reverseFind(characters16(), m_length, c, index); } -size_t StringImpl::reverseFind(StringImpl* matchString, unsigned index) +template <typename CharType> +ALWAYS_INLINE static size_t reverseFindInner(const CharType* searchCharacters, const CharType* matchCharacters, unsigned index, unsigned length, unsigned matchLength) { - // Check for null or empty string to match against - if (!matchString) - return notFound; - unsigned matchLength = matchString->length(); - if (!matchLength) - return min(index, length()); - - // Optimization 1: fast case for strings of length 1. - if (matchLength == 1) { - if (is8Bit() && matchString->is8Bit()) - return WTF::reverseFind(characters8(), length(), matchString->characters8()[0], index); - return WTF::reverseFind(characters(), length(), matchString->characters()[0], index); - } + // Optimization: keep a running hash of the strings, + // only call memcmp if the hashes match. - // Check index & matchLength are in range. - if (matchLength > length()) - return notFound; // delta is the number of additional times to test; delta == 0 means test only once. - unsigned delta = min(index, length() - matchLength); - - const UChar *searchCharacters = characters(); - const UChar *matchCharacters = matchString->characters(); - - // Optimization 2: keep a running hash of the strings, - // only call memcmp if the hashes match. + unsigned delta = min(index, length - matchLength); + unsigned searchHash = 0; unsigned matchHash = 0; for (unsigned i = 0; i < matchLength; ++i) { @@ -971,7 +1009,7 @@ size_t StringImpl::reverseFind(StringImpl* matchString, unsigned index) } // keep looping until we match - while (searchHash != matchHash || memcmp(searchCharacters + delta, matchCharacters, matchLength * sizeof(UChar))) { + while (searchHash != matchHash || memcmp(searchCharacters + delta, matchCharacters, matchLength * sizeof(CharType))) { if (!delta) return notFound; delta--; @@ -981,6 +1019,33 @@ size_t StringImpl::reverseFind(StringImpl* matchString, unsigned index) return delta; } +size_t StringImpl::reverseFind(StringImpl* matchString, unsigned index) +{ + // Check for null or empty string to match against + if (!matchString) + return notFound; + unsigned matchLength = matchString->length(); + unsigned ourLength = length(); + if (!matchLength) + return min(index, ourLength); + + // Optimization 1: fast case for strings of length 1. + if (matchLength == 1) { + if (is8Bit() && matchString->is8Bit()) + return WTF::reverseFind(characters8(), ourLength, matchString->characters8()[0], index); + return WTF::reverseFind(characters(), ourLength, matchString->characters()[0], index); + } + + // Check index & matchLength are in range. + if (matchLength > ourLength) + return notFound; + + if (is8Bit() && matchString->is8Bit()) + return reverseFindInner(characters8(), matchString->characters8(), index, ourLength, matchLength); + + return reverseFindInner(characters(), matchString->characters(), index, ourLength, matchLength); +} + size_t StringImpl::reverseFindIgnoringCase(StringImpl* matchString, unsigned index) { // Check for null or empty string to match against @@ -995,7 +1060,20 @@ size_t StringImpl::reverseFindIgnoringCase(StringImpl* matchString, unsigned ind return notFound; // delta is the number of additional times to test; delta == 0 means test only once. unsigned delta = min(index, length() - matchLength); - + + if (is8Bit() && matchString->is8Bit()) { + const LChar *searchCharacters = characters8(); + const LChar *matchCharacters = matchString->characters8(); + + // keep looping until we match + while (!equalIgnoringCase(searchCharacters + delta, matchCharacters, matchLength)) { + if (!delta) + return notFound; + delta--; + } + return delta; + } + const UChar *searchCharacters = characters(); const UChar *matchCharacters = matchString->characters(); diff --git a/Source/JavaScriptCore/wtf/text/StringImpl.h b/Source/JavaScriptCore/wtf/text/StringImpl.h index 003c44ce6..3862effb6 100644 --- a/Source/JavaScriptCore/wtf/text/StringImpl.h +++ b/Source/JavaScriptCore/wtf/text/StringImpl.h @@ -52,6 +52,7 @@ namespace WTF { struct CStringTranslator; struct HashAndCharactersTranslator; struct HashAndUTF8CharactersTranslator; +struct SubstringTranslator; struct UCharBufferTranslator; enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive }; @@ -68,6 +69,7 @@ class StringImpl { friend struct WTF::CStringTranslator; friend struct WTF::HashAndCharactersTranslator; friend struct WTF::HashAndUTF8CharactersTranslator; + friend struct WTF::SubstringTranslator; friend struct WTF::UCharBufferTranslator; friend class AtomicStringImpl; @@ -190,12 +192,12 @@ private: } public: - ~StringImpl(); + WTF_EXPORT_PRIVATE ~StringImpl(); - static PassRefPtr<StringImpl> create(const UChar*, unsigned length); + WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> create(const UChar*, unsigned length); static PassRefPtr<StringImpl> create(const LChar*, unsigned length); ALWAYS_INLINE static PassRefPtr<StringImpl> create(const char* s, unsigned length) { return create(reinterpret_cast<const LChar*>(s), length); } - static PassRefPtr<StringImpl> create(const LChar*); + WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> create(const LChar*); ALWAYS_INLINE static PassRefPtr<StringImpl> create(const char* s) { return create(reinterpret_cast<const LChar*>(s)); } static ALWAYS_INLINE PassRefPtr<StringImpl> create8(PassRefPtr<StringImpl> rep, unsigned offset, unsigned length) @@ -226,7 +228,7 @@ public: } static PassRefPtr<StringImpl> createUninitialized(unsigned length, LChar*& data); - static PassRefPtr<StringImpl> createUninitialized(unsigned length, UChar*& data); + WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> createUninitialized(unsigned length, UChar*& data); template <typename T> static ALWAYS_INLINE PassRefPtr<StringImpl> tryCreateUninitialized(unsigned length, T*& output) { if (!length) { @@ -275,7 +277,7 @@ public: } static PassRefPtr<StringImpl> adopt(StringBuffer<LChar>& buffer); - static PassRefPtr<StringImpl> adopt(StringBuffer<UChar>& buffer); + WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> adopt(StringBuffer<UChar>& buffer); unsigned length() const { return m_length; } bool is8Bit() const { return m_hashAndFlags & s_hashFlag8BitBuffer; } @@ -308,7 +310,7 @@ public: } bool has16BitShadow() const { return m_hashAndFlags & s_hashFlagHas16BitShadow; } - void upconvertCharacters(unsigned, unsigned) const; + WTF_EXPORT_PRIVATE void upconvertCharacters(unsigned, unsigned) const; bool isIdentifier() const { return m_hashAndFlags & s_hashFlagIsIdentifier; } void setIsIdentifier(bool isIdentifier) { @@ -393,7 +395,7 @@ public: m_refCount -= s_refCountIncrement; } - static StringImpl* empty(); + WTF_EXPORT_PRIVATE static StringImpl* empty(); // FIXME: Does this really belong in StringImpl? template <typename T> static void copyChars(T* destination, const T* source, unsigned numCharacters) @@ -428,7 +430,7 @@ public: // its own copy of the string. PassRefPtr<StringImpl> isolatedCopy() const; - PassRefPtr<StringImpl> substring(unsigned pos, unsigned len = UINT_MAX); + WTF_EXPORT_PRIVATE PassRefPtr<StringImpl> substring(unsigned pos, unsigned len = UINT_MAX); UChar operator[](unsigned i) const { @@ -437,9 +439,9 @@ public: return m_data8[i]; return m_data16[i]; } - UChar32 characterStartingAt(unsigned); + WTF_EXPORT_PRIVATE UChar32 characterStartingAt(unsigned); - bool containsOnlyWhitespace(); + WTF_EXPORT_PRIVATE bool containsOnlyWhitespace(); int toIntStrict(bool* ok = 0, int base = 10); unsigned toUIntStrict(bool* ok = 0, int base = 10); @@ -447,7 +449,7 @@ public: uint64_t toUInt64Strict(bool* ok = 0, int base = 10); intptr_t toIntPtrStrict(bool* ok = 0, int base = 10); - int toInt(bool* ok = 0); // ignores trailing garbage + WTF_EXPORT_PRIVATE int toInt(bool* ok = 0); // ignores trailing garbage unsigned toUInt(bool* ok = 0); // ignores trailing garbage int64_t toInt64(bool* ok = 0); // ignores trailing garbage uint64_t toUInt64(bool* ok = 0); // ignores trailing garbage @@ -456,44 +458,44 @@ public: double toDouble(bool* ok = 0, bool* didReadNumber = 0); float toFloat(bool* ok = 0, bool* didReadNumber = 0); - PassRefPtr<StringImpl> lower(); - PassRefPtr<StringImpl> upper(); + WTF_EXPORT_PRIVATE PassRefPtr<StringImpl> lower(); + WTF_EXPORT_PRIVATE PassRefPtr<StringImpl> upper(); - PassRefPtr<StringImpl> fill(UChar); + WTF_EXPORT_PRIVATE PassRefPtr<StringImpl> fill(UChar); // FIXME: Do we need fill(char) or can we just do the right thing if UChar is ASCII? PassRefPtr<StringImpl> foldCase(); PassRefPtr<StringImpl> stripWhiteSpace(); PassRefPtr<StringImpl> stripWhiteSpace(IsWhiteSpaceFunctionPtr); - PassRefPtr<StringImpl> simplifyWhiteSpace(); + WTF_EXPORT_PRIVATE PassRefPtr<StringImpl> simplifyWhiteSpace(); PassRefPtr<StringImpl> simplifyWhiteSpace(IsWhiteSpaceFunctionPtr); PassRefPtr<StringImpl> removeCharacters(CharacterMatchFunctionPtr); template <typename CharType> ALWAYS_INLINE PassRefPtr<StringImpl> removeCharacters(const CharType* characters, CharacterMatchFunctionPtr); - size_t find(UChar, unsigned index = 0); - size_t find(CharacterMatchFunctionPtr, unsigned index = 0); + WTF_EXPORT_PRIVATE size_t find(UChar, unsigned index = 0); + WTF_EXPORT_PRIVATE size_t find(CharacterMatchFunctionPtr, unsigned index = 0); size_t find(const LChar*, unsigned index = 0); ALWAYS_INLINE size_t find(const char* s, unsigned index = 0) { return find(reinterpret_cast<const LChar*>(s), index); }; - size_t find(StringImpl*, unsigned index = 0); + WTF_EXPORT_PRIVATE size_t find(StringImpl*, unsigned index = 0); size_t findIgnoringCase(const LChar*, unsigned index = 0); ALWAYS_INLINE size_t findIgnoringCase(const char* s, unsigned index = 0) { return findIgnoringCase(reinterpret_cast<const LChar*>(s), index); }; - size_t findIgnoringCase(StringImpl*, unsigned index = 0); + WTF_EXPORT_PRIVATE size_t findIgnoringCase(StringImpl*, unsigned index = 0); - size_t reverseFind(UChar, unsigned index = UINT_MAX); - size_t reverseFind(StringImpl*, unsigned index = UINT_MAX); - size_t reverseFindIgnoringCase(StringImpl*, unsigned index = UINT_MAX); + WTF_EXPORT_PRIVATE size_t reverseFind(UChar, unsigned index = UINT_MAX); + WTF_EXPORT_PRIVATE size_t reverseFind(StringImpl*, unsigned index = UINT_MAX); + WTF_EXPORT_PRIVATE size_t reverseFindIgnoringCase(StringImpl*, unsigned index = UINT_MAX); bool startsWith(StringImpl* str, bool caseSensitive = true) { return (caseSensitive ? reverseFind(str, 0) : reverseFindIgnoringCase(str, 0)) == 0; } - bool endsWith(StringImpl*, bool caseSensitive = true); + WTF_EXPORT_PRIVATE bool endsWith(StringImpl*, bool caseSensitive = true); - PassRefPtr<StringImpl> replace(UChar, UChar); - PassRefPtr<StringImpl> replace(UChar, StringImpl*); - PassRefPtr<StringImpl> replace(StringImpl*, StringImpl*); - PassRefPtr<StringImpl> replace(unsigned index, unsigned len, StringImpl*); + WTF_EXPORT_PRIVATE PassRefPtr<StringImpl> replace(UChar, UChar); + WTF_EXPORT_PRIVATE PassRefPtr<StringImpl> replace(UChar, StringImpl*); + WTF_EXPORT_PRIVATE PassRefPtr<StringImpl> replace(StringImpl*, StringImpl*); + WTF_EXPORT_PRIVATE PassRefPtr<StringImpl> replace(unsigned index, unsigned len, StringImpl*); - WTF::Unicode::Direction defaultWritingDirection(bool* hasStrongDirectionality = 0); + WTF_EXPORT_PRIVATE WTF::Unicode::Direction defaultWritingDirection(bool* hasStrongDirectionality = 0); #if USE(CF) CFStringRef createCFString(); @@ -510,8 +512,8 @@ private: bool isStatic() const { return m_refCount & s_refCountFlagIsStaticString; } template <class UCharPredicate> PassRefPtr<StringImpl> stripMatchedCharacters(UCharPredicate); template <typename CharType, class UCharPredicate> PassRefPtr<StringImpl> simplifyMatchedCharactersToSpace(UCharPredicate); - NEVER_INLINE const UChar* getData16SlowCase() const; - NEVER_INLINE unsigned hashSlowCase() const; + WTF_EXPORT_PRIVATE NEVER_INLINE const UChar* getData16SlowCase() const; + WTF_EXPORT_PRIVATE NEVER_INLINE unsigned hashSlowCase() const; // The bottom bit in the ref count indicates a static (immortal) string. static const unsigned s_refCountFlagIsStaticString = 0x1; @@ -548,16 +550,16 @@ template <> ALWAYS_INLINE const LChar* StringImpl::getCharacters<LChar>() const { return characters8(); } template <> -ALWAYS_INLINE const UChar* StringImpl::getCharacters<UChar>() const { return characters16(); } +ALWAYS_INLINE const UChar* StringImpl::getCharacters<UChar>() const { return characters(); } -bool equal(const StringImpl*, const StringImpl*); -bool equal(const StringImpl*, const LChar*); +WTF_EXPORT_PRIVATE bool equal(const StringImpl*, const StringImpl*); +WTF_EXPORT_PRIVATE bool equal(const StringImpl*, const LChar*); inline bool equal(const StringImpl* a, const char* b) { return equal(a, reinterpret_cast<const LChar*>(b)); } -bool equal(const StringImpl*, const LChar*, unsigned); +WTF_EXPORT_PRIVATE bool equal(const StringImpl*, const LChar*, unsigned); inline bool equal(const StringImpl* a, const char* b, unsigned length) { return equal(a, reinterpret_cast<const LChar*>(b), length); } inline bool equal(const LChar* a, StringImpl* b) { return equal(b, a); } inline bool equal(const char* a, StringImpl* b) { return equal(b, reinterpret_cast<const LChar*>(a)); } -bool equal(const StringImpl*, const UChar*, unsigned); +WTF_EXPORT_PRIVATE bool equal(const StringImpl*, const UChar*, unsigned); // Do comparisons 8 or 4 bytes-at-a-time on architectures where it's safe. #if CPU(X86_64) @@ -715,15 +717,16 @@ ALWAYS_INLINE bool equal(const UChar* a, const LChar* b, unsigned length) return true; } -bool equalIgnoringCase(StringImpl*, StringImpl*); -bool equalIgnoringCase(StringImpl*, const LChar*); +WTF_EXPORT_PRIVATE bool equalIgnoringCase(StringImpl*, StringImpl*); +WTF_EXPORT_PRIVATE bool equalIgnoringCase(StringImpl*, const LChar*); inline bool equalIgnoringCase(const LChar* a, StringImpl* b) { return equalIgnoringCase(b, a); } -bool equalIgnoringCase(const UChar*, const LChar*, unsigned); +WTF_EXPORT_PRIVATE bool equalIgnoringCase(const LChar*, const LChar*, unsigned); +WTF_EXPORT_PRIVATE bool equalIgnoringCase(const UChar*, const LChar*, unsigned); inline bool equalIgnoringCase(const UChar* a, const char* b, unsigned length) { return equalIgnoringCase(a, reinterpret_cast<const LChar*>(b), length); } inline bool equalIgnoringCase(const LChar* a, const UChar* b, unsigned length) { return equalIgnoringCase(b, a, length); } inline bool equalIgnoringCase(const char* a, const UChar* b, unsigned length) { return equalIgnoringCase(b, reinterpret_cast<const LChar*>(a), length); } -bool equalIgnoringNullity(StringImpl*, StringImpl*); +WTF_EXPORT_PRIVATE bool equalIgnoringNullity(StringImpl*, StringImpl*); template<size_t inlineCapacity> bool equalIgnoringNullity(const Vector<UChar, inlineCapacity>& a, StringImpl* b) @@ -735,7 +738,7 @@ bool equalIgnoringNullity(const Vector<UChar, inlineCapacity>& a, StringImpl* b) return !memcmp(a.data(), b->characters(), b->length()); } -int codePointCompare(const StringImpl*, const StringImpl*); +WTF_EXPORT_PRIVATE int codePointCompare(const StringImpl*, const StringImpl*); static inline bool isSpaceOrNewline(UChar c) { diff --git a/Source/JavaScriptCore/wtf/text/WTFString.cpp b/Source/JavaScriptCore/wtf/text/WTFString.cpp index 4c42ed6a2..df74c65af 100644 --- a/Source/JavaScriptCore/wtf/text/WTFString.cpp +++ b/Source/JavaScriptCore/wtf/text/WTFString.cpp @@ -687,6 +687,13 @@ CString String::latin1() const // preserved, characters outside of this range are converted to '?'. unsigned length = this->length(); + + if (!length) + return CString("", 0); + + if (is8Bit()) + return CString(reinterpret_cast<const char*>(this->characters8()), length); + const UChar* characters = this->characters(); char* characterBuffer; diff --git a/Source/JavaScriptCore/wtf/text/WTFString.h b/Source/JavaScriptCore/wtf/text/WTFString.h index 3cecc0afd..2d32e6916 100644 --- a/Source/JavaScriptCore/wtf/text/WTFString.h +++ b/Source/JavaScriptCore/wtf/text/WTFString.h @@ -62,9 +62,9 @@ struct StringHash; // Declarations of string operations -WTF_EXPORT_PRIVATE int charactersToIntStrict(const LChar*, size_t, bool* ok = 0, int base = 10); +int charactersToIntStrict(const LChar*, size_t, bool* ok = 0, int base = 10); WTF_EXPORT_PRIVATE int charactersToIntStrict(const UChar*, size_t, bool* ok = 0, int base = 10); -WTF_EXPORT_PRIVATE unsigned charactersToUIntStrict(const LChar*, size_t, bool* ok = 0, int base = 10); +unsigned charactersToUIntStrict(const LChar*, size_t, bool* ok = 0, int base = 10); WTF_EXPORT_PRIVATE unsigned charactersToUIntStrict(const UChar*, size_t, bool* ok = 0, int base = 10); int64_t charactersToInt64Strict(const LChar*, size_t, bool* ok = 0, int base = 10); int64_t charactersToInt64Strict(const UChar*, size_t, bool* ok = 0, int base = 10); @@ -74,7 +74,7 @@ intptr_t charactersToIntPtrStrict(const LChar*, size_t, bool* ok = 0, int base = intptr_t charactersToIntPtrStrict(const UChar*, size_t, bool* ok = 0, int base = 10); int charactersToInt(const LChar*, size_t, bool* ok = 0); // ignores trailing garbage -int charactersToInt(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage +WTF_EXPORT_PRIVATE int charactersToInt(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage unsigned charactersToUInt(const LChar*, size_t, bool* ok = 0); // ignores trailing garbage unsigned charactersToUInt(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage int64_t charactersToInt64(const LChar*, size_t, bool* ok = 0); // ignores trailing garbage @@ -87,7 +87,7 @@ intptr_t charactersToIntPtr(const UChar*, size_t, bool* ok = 0); // ignores trai WTF_EXPORT_PRIVATE double charactersToDouble(const LChar*, size_t, bool* ok = 0, bool* didReadNumber = 0); WTF_EXPORT_PRIVATE double charactersToDouble(const UChar*, size_t, bool* ok = 0, bool* didReadNumber = 0); float charactersToFloat(const LChar*, size_t, bool* ok = 0, bool* didReadNumber = 0); -float charactersToFloat(const UChar*, size_t, bool* ok = 0, bool* didReadNumber = 0); +WTF_EXPORT_PRIVATE float charactersToFloat(const UChar*, size_t, bool* ok = 0, bool* didReadNumber = 0); enum FloatConversionFlags { ShouldRoundSignificantFigures = 1 << 0, @@ -187,7 +187,7 @@ public: return m_impl->characters()[index]; } - WTF_EXPORT_PRIVATE static String number(short); + static String number(short); WTF_EXPORT_PRIVATE static String number(unsigned short); WTF_EXPORT_PRIVATE static String number(int); WTF_EXPORT_PRIVATE static String number(unsigned); @@ -301,8 +301,8 @@ public: WTF_EXPORT_PRIVATE int toIntStrict(bool* ok = 0, int base = 10) const; WTF_EXPORT_PRIVATE unsigned toUIntStrict(bool* ok = 0, int base = 10) const; WTF_EXPORT_PRIVATE int64_t toInt64Strict(bool* ok = 0, int base = 10) const; - WTF_EXPORT_PRIVATE uint64_t toUInt64Strict(bool* ok = 0, int base = 10) const; - WTF_EXPORT_PRIVATE intptr_t toIntPtrStrict(bool* ok = 0, int base = 10) const; + uint64_t toUInt64Strict(bool* ok = 0, int base = 10) const; + intptr_t toIntPtrStrict(bool* ok = 0, int base = 10) const; WTF_EXPORT_PRIVATE int toInt(bool* ok = 0) const; WTF_EXPORT_PRIVATE unsigned toUInt(bool* ok = 0) const; diff --git a/Source/JavaScriptCore/wtf/unicode/CharacterNames.h b/Source/JavaScriptCore/wtf/unicode/CharacterNames.h index 10fdbf0ef..4acb5f0b1 100644 --- a/Source/JavaScriptCore/wtf/unicode/CharacterNames.h +++ b/Source/JavaScriptCore/wtf/unicode/CharacterNames.h @@ -72,6 +72,7 @@ const UChar rightToLeftEmbed = 0x202B; const UChar rightToLeftMark = 0x200F; const UChar rightToLeftOverride = 0x202E; const UChar sesameDot = 0xFE45; +const UChar smallLetterSharpS = 0x00DF; const UChar softHyphen = 0x00AD; const UChar space = 0x0020; const UChar tibetanMarkIntersyllabicTsheg = 0x0F0B; diff --git a/Source/JavaScriptCore/wtf/unicode/Collator.h b/Source/JavaScriptCore/wtf/unicode/Collator.h index 00ab16e6a..7994ff8e5 100644 --- a/Source/JavaScriptCore/wtf/unicode/Collator.h +++ b/Source/JavaScriptCore/wtf/unicode/Collator.h @@ -45,13 +45,13 @@ namespace WTF { public: enum Result { Equal = 0, Greater = 1, Less = -1 }; - Collator(const char* locale); // Parsing is lenient; e.g. language identifiers (such as "en-US") are accepted, too. - ~Collator(); - void setOrderLowerFirst(bool); + WTF_EXPORT_PRIVATE Collator(const char* locale); // Parsing is lenient; e.g. language identifiers (such as "en-US") are accepted, too. + WTF_EXPORT_PRIVATE ~Collator(); + WTF_EXPORT_PRIVATE void setOrderLowerFirst(bool); static PassOwnPtr<Collator> userDefault(); - Result collate(const ::UChar*, size_t, const ::UChar*, size_t) const; + WTF_EXPORT_PRIVATE Result collate(const ::UChar*, size_t, const ::UChar*, size_t) const; private: #if USE(ICU_UNICODE) && !UCONFIG_NO_COLLATION diff --git a/Source/JavaScriptCore/wtf/unicode/UTF8.h b/Source/JavaScriptCore/wtf/unicode/UTF8.h index bd3dd8a0a..bc2497b72 100644 --- a/Source/JavaScriptCore/wtf/unicode/UTF8.h +++ b/Source/JavaScriptCore/wtf/unicode/UTF8.h @@ -62,7 +62,7 @@ namespace Unicode { // to the replacement character; otherwise (when the flag is set to strict) // they constitute an error. - ConversionResult convertUTF8ToUTF16( + WTF_EXPORT_PRIVATE ConversionResult convertUTF8ToUTF16( const char** sourceStart, const char* sourceEnd, UChar** targetStart, UChar* targetEnd, bool strict = true); @@ -70,7 +70,7 @@ namespace Unicode { const LChar** sourceStart, const LChar* sourceEnd, char** targetStart, char* targetEnd); - ConversionResult convertUTF16ToUTF8( + WTF_EXPORT_PRIVATE ConversionResult convertUTF16ToUTF8( const UChar** sourceStart, const UChar* sourceEnd, char** targetStart, char* targetEnd, bool strict = true); diff --git a/Source/JavaScriptCore/wtf/wtf.pri b/Source/JavaScriptCore/wtf/wtf.pri deleted file mode 100644 index 176949f75..000000000 --- a/Source/JavaScriptCore/wtf/wtf.pri +++ /dev/null @@ -1,42 +0,0 @@ -# ------------------------------------------------------------------- -# This file contains shared rules used both when building WTF itself -# and for targets that depend in some way on WTF. -# -# See 'Tools/qmake/README' for an overview of the build system -# ------------------------------------------------------------------- - -load(features) - -SOURCE_DIR = $${ROOT_WEBKIT_DIR}/Source/JavaScriptCore/wtf - -INCLUDEPATH += \ - $$SOURCE_DIR/.. \ - $$SOURCE_DIR \ - $$SOURCE_DIR/gobject \ - $$SOURCE_DIR/qt \ - $$SOURCE_DIR/unicode - -contains(CONFIG, use_system_icu) { - DEFINES += WTF_USE_ICU_UNICODE=1 - DEFINES -= WTF_USE_QT4_UNICODE - LIBS += -licuuc -licui18n -} else { - DEFINES += WTF_USE_QT4_UNICODE=1 - DEFINES -= WTF_USE_ICU_UNICODE -} - -v8 { - !haveQt(5): error("To build QtWebKit+V8 you need to use Qt 5") - DEFINES *= WTF_USE_V8=1 - INCLUDEPATH += $${ROOT_WEBKIT_DIR}/Source/WebKit/qt/v8/ForwardingHeaders - QT += v8-private declarative -} - -linux-*:!contains(DEFINES, USE_QTMULTIMEDIA=1) { - !contains(QT_CONFIG, no-pkg-config):system(pkg-config --exists glib-2.0 gio-2.0 gstreamer-0.10): { - DEFINES += ENABLE_GLIB_SUPPORT=1 - PKGCONFIG += glib-2.0 gio-2.0 - } -} - -win32-*: LIBS += -lwinmm diff --git a/Source/JavaScriptCore/wtf/wtf.pro b/Source/JavaScriptCore/wtf/wtf.pro deleted file mode 100644 index 234348f2b..000000000 --- a/Source/JavaScriptCore/wtf/wtf.pro +++ /dev/null @@ -1,252 +0,0 @@ -# ------------------------------------------------------------------- -# Project file for WTF -# -# See 'Tools/qmake/README' for an overview of the build system -# ------------------------------------------------------------------- - -TEMPLATE = lib -TARGET = WTF - -include(wtf.pri) - -CONFIG += staticlib - -QT += core -QT -= gui - -*-g++*:QMAKE_CXXFLAGS_RELEASE -= -O2 -*-g++*:QMAKE_CXXFLAGS_RELEASE += -O3 - -HEADERS += \ - Alignment.h \ - AlwaysInline.h \ - ArrayBuffer.h \ - ArrayBufferView.h \ - ASCIICType.h \ - Assertions.h \ - Atomics.h \ - AVLTree.h \ - Bitmap.h \ - BitVector.h \ - BloomFilter.h \ - BoundsCheckedPointer.h \ - BumpPointerAllocator.h \ - ByteArray.h \ - CheckedArithmetic.h \ - Compiler.h \ - CryptographicallyRandomNumber.h \ - CurrentTime.h \ - DateMath.h \ - DecimalNumber.h \ - Decoder.h \ - Deque.h \ - DisallowCType.h \ - dtoa.h \ - dtoa/bignum-dtoa.h \ - dtoa/bignum.h \ - dtoa/cached-powers.h \ - dtoa/diy-fp.h \ - dtoa/double-conversion.h \ - dtoa/double.h \ - dtoa/fast-dtoa.h \ - dtoa/fixed-dtoa.h \ - dtoa/strtod.h \ - dtoa/utils.h \ - DynamicAnnotations.h \ - Encoder.h \ - FastAllocBase.h \ - FastMalloc.h \ - FixedArray.h \ - Float32Array.h \ - Float64Array.h \ - Forward.h \ - Functional.h \ - GetPtr.h \ - HashCountedSet.h \ - HashFunctions.h \ - HashIterators.h \ - HashMap.h \ - HashSet.h \ - HashTable.h \ - HashTraits.h \ - HexNumber.h \ - Int16Array.h \ - Int32Array.h \ - Int8Array.h \ - ListHashSet.h \ - ListRefPtr.h \ - Locker.h \ - MainThread.h \ - MallocZoneSupport.h \ - MathExtras.h \ - MD5.h \ - MessageQueue.h \ - MetaAllocator.h \ - MetaAllocatorHandle.h \ - Noncopyable.h \ - NonCopyingSort.h \ - NotFound.h \ - NullPtr.h \ - OSAllocator.h \ - OSRandomSource.h \ - OwnArrayPtr.h \ - OwnPtr.h \ - OwnPtrCommon.h \ - PackedIntVector.h \ - PageAllocation.h \ - PageAllocationAligned.h \ - PageBlock.h \ - PageReservation.h \ - ParallelJobs.h \ - ParallelJobsGeneric.h \ - ParallelJobsLibdispatch.h \ - ParallelJobsOpenMP.h \ - PassOwnArrayPtr.h \ - PassOwnPtr.h \ - PassRefPtr.h \ - PassTraits.h \ - Platform.h \ - PossiblyNull.h \ - qt/UtilsQt.h \ - RandomNumber.h \ - RandomNumberSeed.h \ - RedBlackTree.h \ - RefCounted.h \ - RefCountedLeakCounter.h \ - RefPtr.h \ - RefPtrHashMap.h \ - RetainPtr.h \ - SHA1.h \ - Spectrum.h \ - StackBounds.h \ - StaticConstructors.h \ - StdLibExtras.h \ - StringExtras.h \ - StringHasher.h \ - TCPackedCache.h \ - TCSpinLock.h \ - TCSystemAlloc.h \ - text/ASCIIFastPath.h \ - text/AtomicString.h \ - text/AtomicStringHash.h \ - text/AtomicStringImpl.h \ - text/CString.h \ - text/StringBuffer.h \ - text/StringBuilder.h \ - text/StringConcatenate.h \ - text/StringHash.h \ - text/StringImpl.h \ - text/StringOperators.h \ - text/TextPosition.h \ - text/WTFString.h \ - Threading.h \ - ThreadingPrimitives.h \ - ThreadRestrictionVerifier.h \ - ThreadSafeRefCounted.h \ - ThreadSpecific.h \ - TypeTraits.h \ - Uint16Array.h \ - Uint32Array.h \ - Uint8Array.h \ - unicode/CharacterNames.h \ - unicode/Collator.h \ - unicode/icu/UnicodeIcu.h \ - unicode/qt4/UnicodeQt4.h \ - unicode/ScriptCodesFromICU.h \ - unicode/Unicode.h \ - unicode/UnicodeMacrosFromICU.h \ - unicode/UTF8.h \ - UnusedParam.h \ - ValueCheck.h \ - Vector.h \ - VectorTraits.h \ - VMTags.h \ - WTFThreadData.h - - -unix: HEADERS += ThreadIdentifierDataPthreads.h - -SOURCES += \ - ArrayBuffer.cpp \ - ArrayBufferView.cpp \ - Assertions.cpp \ - BitVector.cpp \ - ByteArray.cpp \ - CryptographicallyRandomNumber.cpp \ - CurrentTime.cpp \ - DateMath.cpp \ - DecimalNumber.cpp \ - dtoa.cpp \ - dtoa/bignum-dtoa.cc \ - dtoa/bignum.cc \ - dtoa/cached-powers.cc \ - dtoa/diy-fp.cc \ - dtoa/double-conversion.cc \ - dtoa/fast-dtoa.cc \ - dtoa/fixed-dtoa.cc \ - dtoa/strtod.cc \ - FastMalloc.cpp \ - gobject/GOwnPtr.cpp \ - gobject/GRefPtr.cpp \ - HashTable.cpp \ - MD5.cpp \ - MainThread.cpp \ - MetaAllocator.cpp \ - NullPtr.cpp \ - OSRandomSource.cpp \ - qt/MainThreadQt.cpp \ - qt/StringQt.cpp \ - PageAllocationAligned.cpp \ - PageBlock.cpp \ - ParallelJobsGeneric.cpp \ - RandomNumber.cpp \ - RefCountedLeakCounter.cpp \ - SHA1.cpp \ - StackBounds.cpp \ - TCSystemAlloc.cpp \ - Threading.cpp \ - TypeTraits.cpp \ - WTFThreadData.cpp \ - text/AtomicString.cpp \ - text/CString.cpp \ - text/StringBuilder.cpp \ - text/StringImpl.cpp \ - text/StringStatics.cpp \ - text/WTFString.cpp \ - unicode/CollatorDefault.cpp \ - unicode/icu/CollatorICU.cpp \ - unicode/UTF8.cpp - -unix: SOURCES += \ - OSAllocatorPosix.cpp \ - ThreadIdentifierDataPthreads.cpp \ - ThreadingPthreads.cpp - -win*|wince*: SOURCES += \ - OSAllocatorWin.cpp \ - ThreadSpecificWin.cpp \ - ThreadingWin.cpp - -*sh4* { - QMAKE_CXXFLAGS += -mieee -w - QMAKE_CFLAGS += -mieee -w -} - -lessThan(QT_GCC_MAJOR_VERSION, 5) { - # GCC 4.5 and before - lessThan(QT_GCC_MINOR_VERSION, 6) { - # Disable C++0x mode in JSC for those who enabled it in their Qt's mkspec. - *-g++*:QMAKE_CXXFLAGS -= -std=c++0x -std=gnu++0x - } - - # GCC 4.6 and after. - greaterThan(QT_GCC_MINOR_VERSION, 5) { - if (!contains(QMAKE_CXXFLAGS, -std=c++0x) && !contains(QMAKE_CXXFLAGS, -std=gnu++0x)) { - # We need to deactivate those warnings because some names conflicts with upcoming c++0x types (e.g.nullptr). - QMAKE_CFLAGS_WARN_ON += -Wno-c++0x-compat - QMAKE_CXXFLAGS_WARN_ON += -Wno-c++0x-compat - QMAKE_CFLAGS += -Wno-c++0x-compat - QMAKE_CXXFLAGS += -Wno-c++0x-compat - } - } -} diff --git a/Source/JavaScriptCore/yarr/Yarr.h b/Source/JavaScriptCore/yarr/Yarr.h index 501afac5f..3495fc7e4 100644 --- a/Source/JavaScriptCore/yarr/Yarr.h +++ b/Source/JavaScriptCore/yarr/Yarr.h @@ -62,8 +62,8 @@ enum YarrCharSize { Char16 }; -PassOwnPtr<BytecodePattern> byteCompile(YarrPattern&, BumpPointerAllocator*); -int interpret(BytecodePattern*, const UString& input, unsigned start, unsigned length, int* output); +JS_EXPORT_PRIVATE PassOwnPtr<BytecodePattern> byteCompile(YarrPattern&, BumpPointerAllocator*); +JS_EXPORT_PRIVATE int interpret(BytecodePattern*, const UString& input, unsigned start, unsigned length, int* output); } } // namespace JSC::Yarr diff --git a/Source/JavaScriptCore/yarr/YarrInterpreter.cpp b/Source/JavaScriptCore/yarr/YarrInterpreter.cpp index b6bfb2c98..a452bb7f2 100644 --- a/Source/JavaScriptCore/yarr/YarrInterpreter.cpp +++ b/Source/JavaScriptCore/yarr/YarrInterpreter.cpp @@ -565,7 +565,10 @@ public: if (matchEnd == -1) return true; - ASSERT((matchBegin == -1) || (matchBegin <= matchEnd)); + if (matchBegin == -1) + return true; + + ASSERT(matchBegin <= matchEnd); if (matchBegin == matchEnd) return true; @@ -607,7 +610,11 @@ public: int matchBegin = output[(term.atom.subpatternId << 1)]; int matchEnd = output[(term.atom.subpatternId << 1) + 1]; - ASSERT((matchBegin == -1) || (matchBegin <= matchEnd)); + + if (matchBegin == -1) + return false; + + ASSERT(matchBegin <= matchEnd); if (matchBegin == matchEnd) return false; @@ -1443,13 +1450,16 @@ public: int interpret() { + if (input.isNotAvailableInput(0)) + return -1; + + for (unsigned i = 0; i < pattern->m_body->m_numSubpatterns + 1; ++i) + output[i << 1] = -1; + allocatorPool = pattern->m_allocator->startAllocator(); if (!allocatorPool) CRASH(); - for (unsigned i = 0; i < ((pattern->m_body->m_numSubpatterns + 1) << 1); ++i) - output[i] = -1; - DisjunctionContext* context = allocDisjunctionContext(pattern->m_body.get()); JSRegExpResult result = matchDisjunction(pattern->m_body.get(), context, false); @@ -1462,7 +1472,6 @@ public: pattern->m_allocator->stopAllocator(); - // RegExp.cpp currently expects all error to be converted to -1. ASSERT((result == JSRegExpMatch) == (output[0] != -1)); return output[0]; } diff --git a/Source/JavaScriptCore/yarr/YarrJIT.cpp b/Source/JavaScriptCore/yarr/YarrJIT.cpp index a3f467dc1..06faeaa1a 100644 --- a/Source/JavaScriptCore/yarr/YarrJIT.cpp +++ b/Source/JavaScriptCore/yarr/YarrJIT.cpp @@ -2477,6 +2477,14 @@ public: { generateEnter(); + Jump hasInput = checkInput(); + move(TrustedImm32(-1), returnRegister); + generateReturn(); + hasInput.link(this); + + for (unsigned i = 0; i < m_pattern.m_numSubpatterns + 1; ++i) + store32(TrustedImm32(-1), Address(output, (i << 1) * sizeof(int))); + if (!m_pattern.m_body->m_hasFixedSize) store32(index, Address(output)); @@ -2497,7 +2505,7 @@ public: backtrack(); // Link & finalize the code. - LinkBuffer linkBuffer(*globalData, this); + LinkBuffer linkBuffer(*globalData, this, REGEXP_CODE_ID); m_backtrackingState.linkDataLabels(linkBuffer); if (m_charSize == Char8) jitObject.set8BitCode(linkBuffer.finalizeCode()); diff --git a/Source/JavaScriptCore/yarr/YarrPattern.h b/Source/JavaScriptCore/yarr/YarrPattern.h index 2cbb79586..a31deee67 100644 --- a/Source/JavaScriptCore/yarr/YarrPattern.h +++ b/Source/JavaScriptCore/yarr/YarrPattern.h @@ -316,7 +316,7 @@ struct TermChain { }; struct YarrPattern { - YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, const char** error); + JS_EXPORT_PRIVATE YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, const char** error); ~YarrPattern() { |