diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2012-11-09 09:42:44 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2012-11-09 09:42:44 +0100 |
commit | a59391482883479a9b28a6f1ace6d1ebd08a7ecd (patch) | |
tree | fa539db054a20a67bff2fc891c33b0f4ec632916 /Source/JavaScriptCore | |
parent | cfd86b747d32ac22246a1aa908eaa720c63a88c1 (diff) | |
download | qtwebkit-a59391482883479a9b28a6f1ace6d1ebd08a7ecd.tar.gz |
Imported WebKit commit 7bcdfab9a40db7d16b4b95bb77d78b8a59c9e701 (http://svn.webkit.org/repository/webkit/trunk@134025)
New snapshot with numerious build fixes, including MSVC 2012 and ARM Thumb-2.
Diffstat (limited to 'Source/JavaScriptCore')
131 files changed, 5175 insertions, 1332 deletions
diff --git a/Source/JavaScriptCore/API/JSClassRef.cpp b/Source/JavaScriptCore/API/JSClassRef.cpp index 976203f08..f30b02a2a 100644 --- a/Source/JavaScriptCore/API/JSClassRef.cpp +++ b/Source/JavaScriptCore/API/JSClassRef.cpp @@ -134,7 +134,7 @@ OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::JSGlobalData&, OpaqueJSC OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end(); for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) { ASSERT(!it->key->isIdentifier()); - staticValues->add(StringImpl::create(it->key->characters(), it->key->length()), adoptPtr(new StaticValueEntry(it->value->getProperty, it->value->setProperty, it->value->attributes))); + staticValues->add(it->key->isolatedCopy(), adoptPtr(new StaticValueEntry(it->value->getProperty, it->value->setProperty, it->value->attributes))); } } @@ -143,7 +143,7 @@ OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::JSGlobalData&, OpaqueJSC OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end(); for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) { ASSERT(!it->key->isIdentifier()); - staticFunctions->add(StringImpl::create(it->key->characters(), it->key->length()), adoptPtr(new StaticFunctionEntry(it->value->callAsFunction, it->value->attributes))); + staticFunctions->add(it->key->isolatedCopy(), adoptPtr(new StaticFunctionEntry(it->value->callAsFunction, it->value->attributes))); } } } diff --git a/Source/JavaScriptCore/API/JSObjectRef.cpp b/Source/JavaScriptCore/API/JSObjectRef.cpp index 491fa988f..c62efc60d 100644 --- a/Source/JavaScriptCore/API/JSObjectRef.cpp +++ b/Source/JavaScriptCore/API/JSObjectRef.cpp @@ -29,9 +29,9 @@ #include "JSObjectRefPrivate.h" #include "APICast.h" -#include "ButterflyInlineMethods.h" +#include "ButterflyInlines.h" #include "CodeBlock.h" -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "DateConstructor.h" #include "ErrorConstructor.h" #include "FunctionConstructor.h" @@ -144,9 +144,9 @@ JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSVa for (size_t i = 0; i < argumentCount; ++i) argList.append(toJS(exec, arguments[i])); - result = constructArray(exec, argList); + result = constructArray(exec, static_cast<ArrayAllocationProfile*>(0), argList); } else - result = constructEmptyArray(exec); + result = constructEmptyArray(exec, 0); if (exec->hadException()) { if (exception) diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index 393db67c3..bfaca5673 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -40,6 +40,7 @@ SET(JavaScriptCore_SOURCES assembler/MacroAssembler.cpp assembler/LinkBuffer.cpp + bytecode/ArrayAllocationProfile.cpp bytecode/ArrayProfile.cpp bytecode/CallLinkInfo.cpp bytecode/CallLinkStatus.cpp diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 8479ac599..dbe22d11e 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,734 @@ +2012-11-09 Csaba Osztrogonác <ossy@webkit.org> + + [Qt] Fix the LLINT build from ARMv7 platform + https://bugs.webkit.org/show_bug.cgi?id=101712 + + Reviewed by Simon Hausmann. + + Enable generating of LLIntAssembly.h on ARM platforms. + + * DerivedSources.pri: + * JavaScriptCore.pro: + +2012-11-08 Filip Pizlo <fpizlo@apple.com> + + ArrayPrototype.h should have correct indentation + + Rubber stamped by Sam Weinig. + + * runtime/ArrayPrototype.h: + +2012-11-08 Mark Lam <mark.lam@apple.com> + + Renamed ...InlineMethods.h files to ...Inlines.h. + https://bugs.webkit.org/show_bug.cgi?id=101145. + + Reviewed by Geoffrey Garen. + + This is only a refactoring effort to rename the files. There are no + functionality changes. + + * API/JSObjectRef.cpp: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + * dfg/DFGOperations.cpp: + * heap/ConservativeRoots.cpp: + * heap/CopiedBlock.h: + * heap/CopiedSpace.cpp: + * heap/CopiedSpaceInlineMethods.h: Removed. + * heap/CopiedSpaceInlines.h: Copied from Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h. + * heap/CopyVisitor.cpp: + * heap/CopyVisitorInlineMethods.h: Removed. + * heap/CopyVisitorInlines.h: Copied from Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h. + * heap/GCThread.cpp: + * heap/GCThreadSharedData.cpp: + * heap/HandleStack.cpp: + * heap/Heap.cpp: + * heap/HeapRootVisitor.h: + * heap/MarkStack.cpp: + * heap/MarkStackInlineMethods.h: Removed. + * heap/MarkStackInlines.h: Copied from Source/JavaScriptCore/heap/MarkStackInlineMethods.h. + * heap/SlotVisitor.cpp: + * heap/SlotVisitor.h: + * heap/SlotVisitorInlineMethods.h: Removed. + * heap/SlotVisitorInlines.h: Copied from Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h. + * jit/HostCallReturnValue.cpp: + * jit/JIT.cpp: + * jit/JITArithmetic.cpp: + * jit/JITArithmetic32_64.cpp: + * jit/JITCall.cpp: + * jit/JITCall32_64.cpp: + * jit/JITInlineMethods.h: Removed. + * jit/JITInlines.h: Copied from Source/JavaScriptCore/jit/JITInlineMethods.h. + * jit/JITOpcodes.cpp: + * jit/JITOpcodes32_64.cpp: + * jit/JITPropertyAccess.cpp: + * jit/JITPropertyAccess32_64.cpp: + * jsc.cpp: + * runtime/ArrayConstructor.cpp: + * runtime/ArrayPrototype.cpp: + * runtime/ButterflyInlineMethods.h: Removed. + * runtime/ButterflyInlines.h: Copied from Source/JavaScriptCore/runtime/ButterflyInlineMethods.h. + * runtime/IndexingHeaderInlineMethods.h: Removed. + * runtime/IndexingHeaderInlines.h: Copied from Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h. + * runtime/JSActivation.h: + * runtime/JSArray.cpp: + * runtime/JSArray.h: + * runtime/JSCell.h: + * runtime/JSObject.cpp: + * runtime/JSValueInlineMethods.h: Removed. + * runtime/JSValueInlines.h: Copied from Source/JavaScriptCore/runtime/JSValueInlineMethods.h. + * runtime/LiteralParser.cpp: + * runtime/ObjectConstructor.cpp: + * runtime/Operations.h: + * runtime/RegExpMatchesArray.cpp: + * runtime/RegExpObject.cpp: + * runtime/StringPrototype.cpp: + +2012-11-08 Filip Pizlo <fpizlo@apple.com> + + ArrayConstructor.h should have correct indentation + + Rubber stamped by Sam Weinig. + + * runtime/ArrayConstructor.h: + +2012-11-08 Filip Pizlo <fpizlo@apple.com> + + DFG should know that int == null is always false + https://bugs.webkit.org/show_bug.cgi?id=101665 + + Reviewed by Oliver Hunt. + + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + +2012-11-08 Filip Pizlo <fpizlo@apple.com> + + Arguments.h should have correct indentation + + Rubber stamped by Sam Weinig. + + * runtime/Arguments.h: + +2012-11-08 Filip Pizlo <fpizlo@apple.com> + + It should be possible to JIT compile get_by_vals and put_by_vals even if the DFG is disabled. + + Reviewed by Oliver Hunt. + + * jit/JITInlineMethods.h: + (JSC::JIT::chooseArrayMode): + +2012-11-08 Filip Pizlo <fpizlo@apple.com> + + op_call should have LLInt call link info even if the DFG is disabled + https://bugs.webkit.org/show_bug.cgi?id=101672 + + Reviewed by Oliver Hunt. + + Get rid of the evil uses of fall-through. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + +2012-11-08 Oliver Hunt <oliver@apple.com> + + Improve effectiveness of function-level caching + https://bugs.webkit.org/show_bug.cgi?id=101667 + + Reviewed by Filip Pizlo. + + Added a random-eviction based cache for unlinked functions, and switch + UnlinkedFunctionExecutable's code references to Weak<>, thereby letting + us remove the explicit UnlinkedFunctionExecutable::clearCode() calls that + were being triggered by GC. + + Refactored the random eviction part of the CodeCache into a separate data + structure so that I didn't have to duplicate the code again, and then used + that for the new function cache. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::visitChildren): + (JSC::UnlinkedFunctionExecutable::codeBlockFor): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedFunctionExecutable::clearCodeForRecompilation): + (UnlinkedFunctionExecutable): + * debugger/Debugger.cpp: + * runtime/CodeCache.cpp: + (JSC::CodeCache::getCodeBlock): + (JSC::CodeCache::generateFunctionCodeBlock): + (JSC::CodeCache::getFunctionExecutableFromGlobalCode): + (JSC::CodeCache::usedFunctionCode): + (JSC): + * runtime/Executable.cpp: + (JSC::FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling): + (JSC::FunctionExecutable::clearCode): + * runtime/Executable.h: + (FunctionExecutable): + +2012-11-07 Filip Pizlo <fpizlo@apple.com> + + DFG constant folding and CFG simplification should be smart enough to know that if a logical op's operand is proven to have a non-masquerading structure then it always evaluates to true + https://bugs.webkit.org/show_bug.cgi?id=101511 + + Reviewed by Oliver Hunt. + + To make life easier, this moves BranchDirection into BasicBlock so that after + running the CFA, we always know, for each block, what direction the CFA + proved. CFG simplification now both uses and preserves cfaBranchDirection in + its transformations. + + Also made both LogicalNot and Branch check whether the operand is a known cell + with a known structure, and if so, made them do the appropriate folding. + + 5% speed-up on V8/raytrace because it makes raytrace's own null checks + evaporate (i.e. idioms like 'if (!x) throw "unhappiness"') thanks to the fact + that we were already doing structure check hoisting. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::endBasicBlock): + (JSC::DFG::AbstractState::execute): + (JSC::DFG::AbstractState::mergeToSuccessors): + * dfg/DFGAbstractState.h: + (AbstractState): + * dfg/DFGBasicBlock.h: + (JSC::DFG::BasicBlock::BasicBlock): + (BasicBlock): + * dfg/DFGBranchDirection.h: Added. + (DFG): + (JSC::DFG::branchDirectionToString): + (JSC::DFG::isKnownDirection): + (JSC::DFG::branchCondition): + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::run): + (JSC::DFG::CFGSimplificationPhase::mergeBlocks): + +2012-11-08 Christophe Dumez <christophe.dumez@intel.com> + + [JSC] HTML extensions to String.prototype should escape " as " in argument values + https://bugs.webkit.org/show_bug.cgi?id=90667 + + Reviewed by Benjamin Poulain. + + Escape quotation mark as " in argument values to: + - String.prototype.anchor(name) + - String.prototype.fontcolor(color) + - String.prototype.fontsize(size) + - String.prototype.link(href) + + This behavior matches Chromium/V8 and Firefox/Spidermonkey + implementations and is requited by: + http://mathias.html5.org/specs/javascript/#escapeattributevalue + + This also fixes a potential security risk (XSS vector). + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncFontcolor): + (JSC::stringProtoFuncFontsize): + (JSC::stringProtoFuncAnchor): + (JSC::stringProtoFuncLink): + +2012-11-08 Anders Carlsson <andersca@apple.com> + + HeapStatistics::s_pauseTimeStarts and s_pauseTimeEnds should be Vectors + https://bugs.webkit.org/show_bug.cgi?id=101651 + + Reviewed by Andreas Kling. + + HeapStatistics uses Deques when Vectors would work just as good. + + * heap/HeapStatistics.cpp: + * heap/HeapStatistics.h: + (HeapStatistics): + +2012-11-07 Filip Pizlo <fpizlo@apple.com> + + DFG should not assume that something is a double just because it might be undefined + https://bugs.webkit.org/show_bug.cgi?id=101438 + + Reviewed by Oliver Hunt. + + This changes all non-bitop arithmetic to (a) statically expect that variables are + defined prior to use in arithmetic and (b) not fall off into double paths just + because a value may not be a number. This is accomplished with two new notions of + speculation: + + shouldSpeculateIntegerExpectingDefined: Should we speculate that the value is an + integer if we ignore undefined (i.e. SpecOther) predictions? + + shouldSpeculateIntegerForArithmetic: Should we speculate that the value is an + integer if we ignore non-numeric predictions? + + This is a ~2x speed-up on programs that seem to our prediction propagator to have + paths in which otherwise numeric variables are undefined. + + * bytecode/SpeculatedType.h: + (JSC::isInt32SpeculationForArithmetic): + (JSC): + (JSC::isInt32SpeculationExpectingDefined): + (JSC::isDoubleSpeculationForArithmetic): + (JSC::isNumberSpeculationExpectingDefined): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::addShouldSpeculateInteger): + (JSC::DFG::Graph::mulShouldSpeculateInteger): + (JSC::DFG::Graph::negateShouldSpeculateInteger): + (JSC::DFG::Graph::addImmediateShouldSpeculateInteger): + (JSC::DFG::Graph::mulImmediateShouldSpeculateInteger): + * dfg/DFGNode.h: + (JSC::DFG::Node::shouldSpeculateIntegerForArithmetic): + (Node): + (JSC::DFG::Node::shouldSpeculateIntegerExpectingDefined): + (JSC::DFG::Node::shouldSpeculateDoubleForArithmetic): + (JSC::DFG::Node::shouldSpeculateNumberExpectingDefined): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileAdd): + (JSC::DFG::SpeculativeJIT::compileArithMod): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_div): + +2012-11-06 Filip Pizlo <fpizlo@apple.com> + + JSC should infer when indexed storage contains only integers or doubles + https://bugs.webkit.org/show_bug.cgi?id=98606 + + Reviewed by Oliver Hunt. + + This adds two new indexing types: int32 and double. It also adds array allocation profiling, + which allows array allocations to converge to allocating arrays using those types to which + those arrays would have been converted. + + 20% speed-up on navier-stokes. 40% speed-up on various Kraken DSP tests. Some slow-downs too, + but a performance win overall on all benchmarks we track. + + * API/JSObjectRef.cpp: + (JSObjectMakeArray): + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * assembler/AbstractMacroAssembler.h: + (JumpList): + (JSC::AbstractMacroAssembler::JumpList::JumpList): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::branchDouble): + * assembler/X86Assembler.h: + (JSC::X86Assembler::jnp): + (X86Assembler): + (JSC::X86Assembler::X86InstructionFormatter::emitRex): + * bytecode/ArrayAllocationProfile.cpp: Added. + (JSC): + (JSC::ArrayAllocationProfile::updateIndexingType): + * bytecode/ArrayAllocationProfile.h: Added. + (JSC): + (ArrayAllocationProfile): + (JSC::ArrayAllocationProfile::ArrayAllocationProfile): + (JSC::ArrayAllocationProfile::selectIndexingType): + (JSC::ArrayAllocationProfile::updateLastAllocation): + (JSC::ArrayAllocationProfile::selectIndexingTypeFor): + (JSC::ArrayAllocationProfile::updateLastAllocationFor): + * bytecode/ArrayProfile.cpp: + (JSC::ArrayProfile::updatedObservedArrayModes): + (JSC): + * bytecode/ArrayProfile.h: + (JSC): + (JSC::arrayModesInclude): + (JSC::shouldUseSlowPutArrayStorage): + (JSC::shouldUseFastArrayStorage): + (JSC::shouldUseContiguous): + (JSC::shouldUseDouble): + (JSC::shouldUseInt32): + (ArrayProfile): + * bytecode/ByValInfo.h: + (JSC::isOptimizableIndexingType): + (JSC::jitArrayModeForIndexingType): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::updateAllPredictionsAndCountLiveness): + (JSC): + (JSC::CodeBlock::updateAllValueProfilePredictions): + (JSC::CodeBlock::updateAllArrayPredictions): + (JSC::CodeBlock::updateAllPredictions): + (JSC::CodeBlock::shouldOptimizeNow): + * bytecode/CodeBlock.h: + (CodeBlock): + (JSC::CodeBlock::numberOfArrayAllocationProfiles): + (JSC::CodeBlock::addArrayAllocationProfile): + (JSC::CodeBlock::updateAllValueProfilePredictions): + (JSC::CodeBlock::updateAllArrayPredictions): + * bytecode/DFGExitProfile.h: + (JSC::DFG::exitKindToString): + * bytecode/Instruction.h: + (JSC): + (JSC::Instruction::Instruction): + * bytecode/Opcode.h: + (JSC): + (JSC::padOpcodeName): + * bytecode/SpeculatedType.h: + (JSC): + (JSC::isRealNumberSpeculation): + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): + * bytecode/UnlinkedCodeBlock.h: + (JSC): + (JSC::UnlinkedCodeBlock::addArrayAllocationProfile): + (JSC::UnlinkedCodeBlock::numberOfArrayAllocationProfiles): + (UnlinkedCodeBlock): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::newArrayAllocationProfile): + (JSC): + (JSC::BytecodeGenerator::emitNewArray): + (JSC::BytecodeGenerator::emitExpectedFunctionSnippet): + * bytecompiler/BytecodeGenerator.h: + (BytecodeGenerator): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGArrayMode.cpp: + (JSC::DFG::ArrayMode::fromObserved): + (JSC::DFG::ArrayMode::refine): + (DFG): + (JSC::DFG::ArrayMode::alreadyChecked): + (JSC::DFG::arrayTypeToString): + * dfg/DFGArrayMode.h: + (JSC::DFG::ArrayMode::withType): + (ArrayMode): + (JSC::DFG::ArrayMode::withTypeAndConversion): + (JSC::DFG::ArrayMode::usesButterfly): + (JSC::DFG::ArrayMode::isSpecific): + (JSC::DFG::ArrayMode::supportsLength): + (JSC::DFG::ArrayMode::arrayModesThatPassFiltering): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::getArrayMode): + (ByteCodeParser): + (JSC::DFG::ByteCodeParser::handleIntrinsic): + (JSC::DFG::ByteCodeParser::handleConstantInternalFunction): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCCallHelpers.h: + (JSC::DFG::CCallHelpers::setupArgumentsWithExecState): + (CCallHelpers): + * dfg/DFGCallArrayAllocatorSlowPathGenerator.h: + (JSC::DFG::CallArrayAllocatorSlowPathGenerator::generateInternal): + (JSC::DFG::CallArrayAllocatorWithVariableSizeSlowPathGenerator::generateInternal): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::checkArray): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::byValIsPure): + * dfg/DFGNode.h: + (NewArrayBufferData): + (JSC::DFG::Node::hasIndexingType): + (Node): + (JSC::DFG::Node::indexingType): + (JSC::DFG::Node::setIndexingType): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitAllocateJSArray): + (JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode): + (DFG): + (JSC::DFG::SpeculativeJIT::checkArray): + (JSC::DFG::SpeculativeJIT::arrayify): + (JSC::DFG::SpeculativeJIT::compileDoublePutByVal): + (JSC::DFG::SpeculativeJIT::compileGetArrayLength): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + (SpeculativeJIT): + (SpeculateIntegerOperand): + (JSC::DFG::SpeculateIntegerOperand::use): + (SpeculateDoubleOperand): + (JSC::DFG::SpeculateDoubleOperand::use): + * dfg/DFGSpeculativeJIT32_64.cpp: + (DFG): + (JSC::DFG::SpeculativeJIT::compileContiguousPutByVal): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JIT.h: + (JSC::JIT::emitInt32GetByVal): + (JIT): + (JSC::JIT::emitInt32PutByVal): + (JSC::JIT::emitDoublePutByVal): + (JSC::JIT::emitContiguousPutByVal): + * jit/JITExceptions.cpp: + (JSC::genericThrow): + * jit/JITInlineMethods.h: + (JSC::arrayProfileSaw): + (JSC::JIT::chooseArrayMode): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_new_array): + (JSC::JIT::emit_op_new_array_with_size): + (JSC::JIT::emit_op_new_array_buffer): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emitDoubleGetByVal): + (JSC): + (JSC::JIT::emitContiguousGetByVal): + (JSC::JIT::emit_op_put_by_val): + (JSC::JIT::emitGenericContiguousPutByVal): + (JSC::JIT::emitSlow_op_put_by_val): + (JSC::JIT::privateCompileGetByVal): + (JSC::JIT::privateCompilePutByVal): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emitContiguousGetByVal): + (JSC::JIT::emitDoubleGetByVal): + (JSC): + (JSC::JIT::emit_op_put_by_val): + (JSC::JIT::emitGenericContiguousPutByVal): + (JSC::JIT::emitSlow_op_put_by_val): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * jit/JITStubs.h: + (JSC): + * jsc.cpp: + (GlobalObject::finishCreation): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::jitCompileAndSetHeuristics): + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * offlineasm/x86.rb: + * runtime/ArrayConstructor.cpp: + (JSC::constructArrayWithSizeQuirk): + * runtime/ArrayConstructor.h: + (JSC): + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncConcat): + (JSC::arrayProtoFuncSlice): + (JSC::arrayProtoFuncSplice): + (JSC::arrayProtoFuncFilter): + (JSC::arrayProtoFuncMap): + * runtime/Butterfly.h: + (JSC::Butterfly::contiguousInt32): + (JSC::Butterfly::contiguousDouble): + (JSC::Butterfly::fromContiguous): + * runtime/ButterflyInlineMethods.h: + (JSC::Butterfly::createUninitializedDuringCollection): + * runtime/FunctionPrototype.cpp: + (JSC::functionProtoFuncBind): + * runtime/IndexingHeaderInlineMethods.h: + (JSC::IndexingHeader::indexingPayloadSizeInBytes): + * runtime/IndexingType.cpp: + (JSC::leastUpperBoundOfIndexingTypes): + (JSC): + (JSC::leastUpperBoundOfIndexingTypeAndType): + (JSC::leastUpperBoundOfIndexingTypeAndValue): + (JSC::indexingTypeToString): + * runtime/IndexingType.h: + (JSC): + (JSC::hasUndecided): + (JSC::hasInt32): + (JSC::hasDouble): + * runtime/JSArray.cpp: + (JSC::JSArray::setLength): + (JSC::JSArray::pop): + (JSC::JSArray::push): + (JSC::JSArray::shiftCountWithAnyIndexingType): + (JSC::JSArray::unshiftCountWithAnyIndexingType): + (JSC::compareNumbersForQSortWithInt32): + (JSC): + (JSC::compareNumbersForQSortWithDouble): + (JSC::JSArray::sortNumericVector): + (JSC::JSArray::sortNumeric): + (JSC::JSArray::sortCompactedVector): + (JSC::JSArray::sort): + (JSC::JSArray::sortVector): + (JSC::JSArray::fillArgList): + (JSC::JSArray::copyToArguments): + (JSC::JSArray::compactForSorting): + * runtime/JSArray.h: + (JSArray): + (JSC::createContiguousArrayButterfly): + (JSC::JSArray::create): + (JSC::JSArray::tryCreateUninitialized): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + (JSC): + (JSC::JSGlobalObject::haveABadTime): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSGlobalObject): + (JSC::JSGlobalObject::originalArrayStructureForIndexingType): + (JSC::JSGlobalObject::arrayStructureForIndexingTypeDuringAllocation): + (JSC::JSGlobalObject::arrayStructureForProfileDuringAllocation): + (JSC::JSGlobalObject::isOriginalArrayStructure): + (JSC::constructEmptyArray): + (JSC::constructArray): + * runtime/JSObject.cpp: + (JSC::JSObject::copyButterfly): + (JSC::JSObject::getOwnPropertySlotByIndex): + (JSC::JSObject::putByIndex): + (JSC::JSObject::enterDictionaryIndexingMode): + (JSC::JSObject::createInitialIndexedStorage): + (JSC): + (JSC::JSObject::createInitialUndecided): + (JSC::JSObject::createInitialInt32): + (JSC::JSObject::createInitialDouble): + (JSC::JSObject::createInitialContiguous): + (JSC::JSObject::convertUndecidedToInt32): + (JSC::JSObject::convertUndecidedToDouble): + (JSC::JSObject::convertUndecidedToContiguous): + (JSC::JSObject::constructConvertedArrayStorageWithoutCopyingElements): + (JSC::JSObject::convertUndecidedToArrayStorage): + (JSC::JSObject::convertInt32ToDouble): + (JSC::JSObject::convertInt32ToContiguous): + (JSC::JSObject::convertInt32ToArrayStorage): + (JSC::JSObject::convertDoubleToContiguous): + (JSC::JSObject::convertDoubleToArrayStorage): + (JSC::JSObject::convertContiguousToArrayStorage): + (JSC::JSObject::convertUndecidedForValue): + (JSC::JSObject::convertInt32ForValue): + (JSC::JSObject::setIndexQuicklyToUndecided): + (JSC::JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex): + (JSC::JSObject::convertDoubleToContiguousWhilePerformingSetIndex): + (JSC::JSObject::ensureInt32Slow): + (JSC::JSObject::ensureDoubleSlow): + (JSC::JSObject::ensureContiguousSlow): + (JSC::JSObject::ensureArrayStorageSlow): + (JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode): + (JSC::JSObject::switchToSlowPutArrayStorage): + (JSC::JSObject::deletePropertyByIndex): + (JSC::JSObject::getOwnPropertyNames): + (JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes): + (JSC::JSObject::putByIndexBeyondVectorLength): + (JSC::JSObject::putDirectIndexBeyondVectorLength): + (JSC::JSObject::getNewVectorLength): + (JSC::JSObject::countElements): + (JSC::JSObject::ensureLengthSlow): + (JSC::JSObject::getOwnPropertyDescriptor): + * runtime/JSObject.h: + (JSC::JSObject::getArrayLength): + (JSC::JSObject::getVectorLength): + (JSC::JSObject::canGetIndexQuickly): + (JSC::JSObject::getIndexQuickly): + (JSC::JSObject::tryGetIndexQuickly): + (JSC::JSObject::canSetIndexQuickly): + (JSC::JSObject::canSetIndexQuicklyForPutDirect): + (JSC::JSObject::setIndexQuickly): + (JSC::JSObject::initializeIndex): + (JSC::JSObject::hasSparseMap): + (JSC::JSObject::inSparseIndexingMode): + (JSObject): + (JSC::JSObject::ensureInt32): + (JSC::JSObject::ensureDouble): + (JSC::JSObject::ensureLength): + (JSC::JSObject::indexingData): + (JSC::JSObject::currentIndexingData): + (JSC::JSObject::getHolyIndexQuickly): + (JSC::JSObject::relevantLength): + (JSC::JSObject::currentRelevantLength): + * runtime/JSValue.cpp: + (JSC::JSValue::description): + * runtime/LiteralParser.cpp: + (JSC::::parse): + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorGetOwnPropertyNames): + (JSC::objectConstructorKeys): + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncMatch): + (JSC::stringProtoFuncSplit): + * runtime/Structure.cpp: + (JSC::Structure::nonPropertyTransition): + * runtime/StructureTransitionTable.h: + (JSC::newIndexingType): + +2012-11-08 Balazs Kilvady <kilvadyb@homejinni.com> + + ASSERT problem on MIPS + https://bugs.webkit.org/show_bug.cgi?id=100589 + + Reviewed by Oliver Hunt. + + ASSERT fix for MIPS arch. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_resolve_operations): + +2012-11-08 Michael Saboff <msaboff@apple.com> + + OpaqueJSClassContextData() should use StringImpl::isolatedCopy() to make string copies + https://bugs.webkit.org/show_bug.cgi?id=101507 + + Reviewed by Andreas Kling. + + Changed to use isolatedCopy() for key Strings. + + * API/JSClassRef.cpp: + (OpaqueJSClassContextData::OpaqueJSClassContextData): + +2012-11-07 Mark Hahnenberg <mhahnenberg@apple.com> + + WeakBlocks should be HeapBlocks + https://bugs.webkit.org/show_bug.cgi?id=101411 + + Reviewed by Oliver Hunt. + + Currently WeakBlocks use fastMalloc memory. They are very similar to the other HeapBlocks, however, + so we should change them to being allocated with the BlockAllocator. + + * heap/BlockAllocator.cpp: + (JSC::BlockAllocator::BlockAllocator): + * heap/BlockAllocator.h: Added a new RegionSet for WeakBlocks. + (JSC): + (BlockAllocator): + (JSC::WeakBlock): + * heap/Heap.h: Friended WeakSet to allow access to the BlockAllocator. + (Heap): + * heap/WeakBlock.cpp: + (JSC::WeakBlock::create): Refactored to use HeapBlocks rather than fastMalloc. + (JSC::WeakBlock::WeakBlock): + * heap/WeakBlock.h: Changed the WeakBlock size to 4 KB so that it divides evenly into the Region size. + (JSC): + (WeakBlock): + * heap/WeakSet.cpp: + (JSC::WeakSet::~WeakSet): + (JSC::WeakSet::addAllocator): + +2012-11-07 Filip Pizlo <fpizlo@apple.com> + + Indentation of ArgList.h is wrong + https://bugs.webkit.org/show_bug.cgi?id=101441 + + Reviewed by Andreas Kling. + + Just unindented by 4 spaces. + + * runtime/ArgList.h: + +2012-11-07 Gabor Ballabas <gaborb@inf.u-szeged.hu> + + [Qt][ARM] REGRESSION(r133688): It made all JSC and layout tests crash on ARM traditional platform + https://bugs.webkit.org/show_bug.cgi?id=101465 + + Reviewed by Oliver Hunt. + + Fix failing javascriptcore tests on ARM after r133688 + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + 2012-11-06 Oliver Hunt <oliver@apple.com> Reduce parser overhead in JSC diff --git a/Source/JavaScriptCore/Configurations/Version.xcconfig b/Source/JavaScriptCore/Configurations/Version.xcconfig index 3d24fe85a..f2d37774e 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 = 537; -MINOR_VERSION = 18; +MINOR_VERSION = 19; TINY_VERSION = 0; FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION); diff --git a/Source/JavaScriptCore/DerivedSources.pri b/Source/JavaScriptCore/DerivedSources.pri index 03a935575..f9bbbf67c 100644 --- a/Source/JavaScriptCore/DerivedSources.pri +++ b/Source/JavaScriptCore/DerivedSources.pri @@ -102,7 +102,7 @@ for(dir, DIRS) { exists($$file): LLINT_FILES += $$file } -if(linux-*|win32):!equals(QT_ARCH, "arm") { +if(linux-*|win32) { #GENERATOR: LLInt llint.output = ${QMAKE_FILE_IN_PATH}$${QMAKE_DIR_SEP}LLIntAssembly.h llint.script = $$PWD/offlineasm/asm.rb diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index d68a22b9f..6c7eac9e3 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -83,6 +83,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/assembler/RepatchBuffer.h \ Source/JavaScriptCore/assembler/SH4Assembler.h \ Source/JavaScriptCore/assembler/X86Assembler.h \ + Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp \ + Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h \ Source/JavaScriptCore/bytecode/ArrayProfile.cpp \ Source/JavaScriptCore/bytecode/ArrayProfile.h \ Source/JavaScriptCore/bytecode/ByValInfo.h \ @@ -254,9 +256,9 @@ javascriptcore_sources += \ Source/JavaScriptCore/heap/CopiedBlock.h \ Source/JavaScriptCore/heap/CopiedSpace.cpp \ Source/JavaScriptCore/heap/CopiedSpace.h \ - Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h \ + Source/JavaScriptCore/heap/CopiedSpaceInlines.h \ Source/JavaScriptCore/heap/CopyVisitor.h \ - Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h \ + Source/JavaScriptCore/heap/CopyVisitorInlines.h \ Source/JavaScriptCore/heap/CopyVisitor.cpp \ Source/JavaScriptCore/heap/CardSet.h \ Source/JavaScriptCore/heap/ConservativeRoots.cpp \ @@ -274,7 +276,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/heap/IncrementalSweeper.cpp \ Source/JavaScriptCore/heap/SlotVisitor.cpp \ Source/JavaScriptCore/heap/SlotVisitor.h \ - Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h \ + Source/JavaScriptCore/heap/SlotVisitorInlines.h \ Source/JavaScriptCore/heap/HandleStack.cpp \ Source/JavaScriptCore/heap/HandleStack.h \ Source/JavaScriptCore/heap/HandleTypes.h \ @@ -297,7 +299,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/heap/MachineStackMarker.h \ Source/JavaScriptCore/heap/MarkStack.cpp \ Source/JavaScriptCore/heap/MarkStack.h \ - Source/JavaScriptCore/heap/MarkStackInlineMethods.h \ + Source/JavaScriptCore/heap/MarkStackInlines.h \ Source/JavaScriptCore/heap/HeapRootVisitor.h \ Source/JavaScriptCore/heap/MarkedAllocator.cpp \ Source/JavaScriptCore/heap/MarkedAllocator.h \ @@ -398,7 +400,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/jit/JIT.h \ Source/JavaScriptCore/jit/JITExceptions.cpp \ Source/JavaScriptCore/jit/JITExceptions.h \ - Source/JavaScriptCore/jit/JITInlineMethods.h \ + Source/JavaScriptCore/jit/JITInlines.h \ Source/JavaScriptCore/jit/JITOpcodes32_64.cpp \ Source/JavaScriptCore/jit/JITOpcodes.cpp \ Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp \ @@ -481,7 +483,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/BooleanObject.h \ Source/JavaScriptCore/runtime/BooleanPrototype.cpp \ Source/JavaScriptCore/runtime/BooleanPrototype.h \ - Source/JavaScriptCore/runtime/ButterflyInlineMethods.h \ + Source/JavaScriptCore/runtime/ButterflyInlines.h \ Source/JavaScriptCore/runtime/Butterfly.h \ Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h \ Source/JavaScriptCore/runtime/CallData.cpp \ @@ -529,7 +531,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/GetterSetter.h \ Source/JavaScriptCore/runtime/Identifier.cpp \ Source/JavaScriptCore/runtime/Identifier.h \ - Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h \ + Source/JavaScriptCore/runtime/IndexingHeaderInlines.h \ Source/JavaScriptCore/runtime/IndexingHeader.h \ Source/JavaScriptCore/runtime/IndexingType.cpp \ Source/JavaScriptCore/runtime/IndexingType.h \ @@ -590,7 +592,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/JSTypeInfo.h \ Source/JavaScriptCore/runtime/JSValue.cpp \ Source/JavaScriptCore/runtime/JSValue.h \ - Source/JavaScriptCore/runtime/JSValueInlineMethods.h \ + Source/JavaScriptCore/runtime/JSValueInlines.h \ Source/JavaScriptCore/runtime/JSVariableObject.cpp \ Source/JavaScriptCore/runtime/JSVariableObject.h \ Source/JavaScriptCore/runtime/JSWithScope.h \ diff --git a/Source/JavaScriptCore/JavaScriptCore.pro b/Source/JavaScriptCore/JavaScriptCore.pro index c86ca8e3d..924261d4f 100644 --- a/Source/JavaScriptCore/JavaScriptCore.pro +++ b/Source/JavaScriptCore/JavaScriptCore.pro @@ -7,7 +7,7 @@ TEMPLATE = subdirs CONFIG += ordered -if(linux-*|win32*):!equals(QT_ARCH, "arm") { +if(linux-*|win32*) { LLIntOffsetsExtractor.file = LLIntOffsetsExtractor.pro LLIntOffsetsExtractor.makefile = Makefile.LLIntOffsetsExtractor SUBDIRS += LLIntOffsetsExtractor @@ -18,7 +18,7 @@ target.file = Target.pri SUBDIRS += derived_sources target -if(linux-*|win32*):!equals(QT_ARCH, "arm"):addStrictSubdirOrderBetween(LLIntOffsetsExtractor, derived_sources) +if(linux-*|win32*):addStrictSubdirOrderBetween(LLIntOffsetsExtractor, derived_sources) addStrictSubdirOrderBetween(derived_sources, target) jsc.file = jsc.pro diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index b23100547..e57335015 100755 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -54,6 +54,7 @@ EXPORTS ?absoluteTimeToWaitTimeoutInterval@WTF@@YAKN@Z ?activityCallback@Heap@JSC@@QAEPAVGCActivityCallback@2@XZ ?add@AtomicString@WTF@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@2@PBD@Z + ?addFromLiteralData@AtomicString@WTF@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@2@PBDI@Z ?add@Identifier@JSC@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVJSGlobalData@2@PAVStringImpl@4@@Z ?add@Identifier@JSC@@SA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVExecState@2@PBD@Z ?add@PropertyNameArray@JSC@@QAEXPAVStringImpl@WTF@@@Z @@ -110,11 +111,12 @@ EXPORTS ?computeHash@SHA1@WTF@@QAEXAAV?$Vector@E$0BE@@2@@Z ?configurable@PropertyDescriptor@JSC@@QBE_NXZ ?construct@JSC@@YAPAVJSObject@1@PAVExecState@1@VJSValue@1@W4ConstructType@1@ABTConstructData@1@ABVArgList@1@@Z - ?constructArray@JSC@@YAPAVJSArray@1@PAVExecState@1@ABVArgList@1@@Z ?constructEmptyObject@JSC@@YAPAVJSObject@1@PAVExecState@1@@Z ?constructFunctionSkippingEvalEnabledCheck@JSC@@YAPAVJSObject@1@PAVExecState@1@PAVJSGlobalObject@1@ABVArgList@1@ABVIdentifier@1@ABVString@WTF@@ABVTextPosition@8@@Z ?constructNumber@JSC@@YAPAVNumberObject@1@PAVExecState@1@PAVJSGlobalObject@1@VJSValue@1@@Z ?constructString@JSC@@YAPAVStringObject@1@PAVExecState@1@PAVJSGlobalObject@1@VJSValue@1@@Z + ?convertDoubleToContiguousWhilePerformingSetIndex@JSObject@JSC@@AAEXAAVJSGlobalData@2@IVJSValue@2@@Z + ?convertInt32ToDoubleOrContiguousWhilePerformingSetIndex@JSObject@JSC@@AAEXAAVJSGlobalData@2@IVJSValue@2@@Z ?convertLatin1ToUTF8@Unicode@WTF@@YA?AW4ConversionResult@12@PAPBEPBEPAPADPAD@Z ?convertUTF16ToUTF8@Unicode@WTF@@YA?AW4ConversionResult@12@PAPB_WPB_WPAPADPAD_N@Z ?convertUTF8ToUTF16@Unicode@WTF@@YA?AW4ConversionResult@12@PAPBDPBDPAPA_WPA_WPA_N_N@Z @@ -333,6 +335,7 @@ EXPORTS ?setGarbageCollectionTimerEnabled@Heap@JSC@@QAEX_N@Z ?setGetter@PropertyDescriptor@JSC@@QAEXVJSValue@2@@Z ?setGlobalThis@JSGlobalObject@JSC@@IAEXAAVJSGlobalData@2@PAVJSObject@2@@Z + ?setIndexQuicklyToUndecided@JSObject@JSC@@AAEXAAVJSGlobalData@2@IVJSValue@2@@Z ?setLoc@StatementNode@JSC@@QAEXHH@Z ?setMainThreadCallbacksPaused@WTF@@YAX_N@Z ?setOption@Options@JSC@@SA_NPBD@Z @@ -402,6 +405,7 @@ EXPORTS ?unlock@Mutex@WTF@@QAEXXZ ?unlockAtomicallyInitializedStaticMutex@WTF@@YAXXZ ?unprotect@Heap@JSC@@QAE_NVJSValue@2@@Z + ?updateIndexingType@ArrayAllocationProfile@JSC@@QAEXXZ ?validate@SlotVisitor@JSC@@CAXPAVJSCell@2@@Z ?visitChildren@JSGlobalObject@JSC@@SAXPAVJSCell@2@AAVSlotVisitor@2@@Z ?visitChildren@JSObject@JSC@@SAXPAVJSCell@2@AAVSlotVisitor@2@@Z diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj index b1567e2cd..0e732d187 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -538,7 +538,7 @@ >
</File>
<File
- RelativePath="..\..\runtime\ButterflyInlineMethods.h"
+ RelativePath="..\..\runtime\ButterflyInlines.h"
>
</File>
<File
@@ -546,7 +546,7 @@ >
</File>
<File
- RelativePath="..\..\runtime\IndexingHeaderInlineMethods.h"
+ RelativePath="..\..\runtime\IndexingHeaderInlines.h"
>
</File>
<File
@@ -1010,7 +1010,7 @@ >
</File>
<File
- RelativePath="..\..\runtime\JSValueInlineMethods.h"
+ RelativePath="..\..\runtime\JSValueInlines.h"
>
</File>
<File
@@ -1582,6 +1582,14 @@ Name="bytecode"
>
<File
+ RelativePath="..\..\bytecode\ArrayAllocationProfile.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\bytecode\ArrayAllocationProfile.h"
+ >
+ </File>
+ <File
RelativePath="..\..\bytecode\ArrayProfile.cpp"
>
</File>
@@ -1978,7 +1986,7 @@ >
</File>
<File
- RelativePath="..\..\jit\JITInlineMethods.h"
+ RelativePath="..\..\jit\JITInlines.h"
>
</File>
<File
@@ -2354,7 +2362,7 @@ >
</File>
<File
- RelativePath="..\..\heap\CopiedSpaceInlineMethods.h"
+ RelativePath="..\..\heap\CopiedSpaceInlines.h"
>
</File>
<File
@@ -2366,7 +2374,7 @@ >
</File>
<File
- RelativePath="..\..\heap\CopyVisitorInlineMethods.h"
+ RelativePath="..\..\heap\CopyVisitorInlines.h"
>
</File>
<File
@@ -2554,7 +2562,7 @@ >
</File>
<File
- RelativePath="..\..\heap\MarkStackInlineMethods.h"
+ RelativePath="..\..\heap\MarkStackInlines.h"
>
</File>
<File
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 3cada1cd7..87747ca6d 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -165,6 +165,9 @@ 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, ); }; }; 0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8023E91613832300A0BA45 /* ByValInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */; }; + 0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F919D0C157EE09F004A4E7D /* JSSymbolTableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */; }; 0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F919D10157F3329004A4E7D /* JSSegmentedVariableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */; }; @@ -193,9 +196,9 @@ 0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38915ED8E3800F167B2 /* ArrayConventions.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FB7F39615ED8E4600F167B2 /* ArrayStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FB7F39715ED8E4600F167B2 /* Butterfly.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38B15ED8E3800F167B2 /* Butterfly.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 0FB7F39815ED8E4600F167B2 /* ButterflyInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38C15ED8E3800F167B2 /* ButterflyInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FB7F39815ED8E4600F167B2 /* ButterflyInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FB7F39915ED8E4600F167B2 /* IndexingHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38D15ED8E3800F167B2 /* IndexingHeader.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 0FB7F39A15ED8E4600F167B2 /* IndexingHeaderInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FB7F39A15ED8E4600F167B2 /* IndexingHeaderInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FB7F39B15ED8E4600F167B2 /* IndexingType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38F15ED8E3800F167B2 /* IndexingType.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FB7F39D15ED8E4600F167B2 /* Reject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39115ED8E3800F167B2 /* Reject.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -450,7 +453,7 @@ 863C6D9C1521111A00585E4E /* YarrCanonicalizeUCS2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 863C6D981521111200585E4E /* YarrCanonicalizeUCS2.cpp */; }; 8642C510151C06A90046D4EF /* RegExpCachedResult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86F75EFB151C062F007C9BA3 /* RegExpCachedResult.cpp */; }; 8642C512151C083D0046D4EF /* RegExpMatchesArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86F75EFD151C062F007C9BA3 /* RegExpMatchesArray.cpp */; }; - 865A30F1135007E100CDB49E /* JSValueInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 865A30F0135007E100CDB49E /* JSValueInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 865A30F1135007E100CDB49E /* JSValueInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 865A30F0135007E100CDB49E /* JSValueInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; 865F408810E7D56300947361 /* APIShims.h in Headers */ = {isa = PBXBuildFile; fileRef = 865F408710E7D56300947361 /* APIShims.h */; settings = {ATTRIBUTES = (Private, ); }; }; 866739D213BFDE710023D87C /* BigInteger.h in Headers */ = {isa = PBXBuildFile; fileRef = 866739D013BFDE710023D87C /* BigInteger.h */; }; 866739D313BFDE710023D87C /* Uint16WithFraction.h in Headers */ = {isa = PBXBuildFile; fileRef = 866739D113BFDE710023D87C /* Uint16WithFraction.h */; }; @@ -486,7 +489,7 @@ 86C568E211A213EE0007F7F0 /* MIPSAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C568DF11A213EE0007F7F0 /* MIPSAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86CA032E1038E8440028A609 /* Executable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CA032D1038E8440028A609 /* Executable.cpp */; }; 86CAFEE31035DDE60028A609 /* Executable.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CAFEE21035DDE60028A609 /* Executable.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 86CC85A10EE79A4700288682 /* JITInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CC85A00EE79A4700288682 /* JITInlineMethods.h */; }; + 86CC85A10EE79A4700288682 /* JITInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CC85A00EE79A4700288682 /* JITInlines.h */; }; 86CC85A30EE79B7400288682 /* JITCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CC85A20EE79B7400288682 /* JITCall.cpp */; }; 86CC85C40EE7A89400288682 /* JITPropertyAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CC85C30EE7A89400288682 /* JITPropertyAccess.cpp */; }; 86CCEFDE0F413F8900FD7F9E /* JITCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CCEFDD0F413F8900FD7F9E /* JITCode.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -711,11 +714,11 @@ BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFD8C910EEB2EE700283848 /* JumpTable.h */; }; C21122E115DD9AB300790E3A /* GCThreadSharedData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */; }; C21122E215DD9AB300790E3A /* GCThreadSharedData.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */; settings = {ATTRIBUTES = (Private, ); }; }; - C21122E315DD9AB300790E3A /* MarkStackInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; - C2160FE715F7E95E00942DFC /* SlotVisitorInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCB408515C0A3C30048932B /* SlotVisitorInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C21122E315DD9AB300790E3A /* MarkStackInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122E015DD9AB300790E3A /* MarkStackInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C2160FE715F7E95E00942DFC /* SlotVisitorInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2239D1716262BDD005AC5FD /* CopyVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2239D1216262BDD005AC5FD /* CopyVisitor.cpp */; }; C2239D1816262BDD005AC5FD /* CopyVisitor.h in Headers */ = {isa = PBXBuildFile; fileRef = C2239D1316262BDD005AC5FD /* CopyVisitor.h */; settings = {ATTRIBUTES = (Private, ); }; }; - C2239D1916262BDD005AC5FD /* CopyVisitorInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = C2239D1416262BDD005AC5FD /* CopyVisitorInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C2239D1916262BDD005AC5FD /* CopyVisitorInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C2239D1416262BDD005AC5FD /* CopyVisitorInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2239D1A16262BDD005AC5FD /* GCThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2239D1516262BDD005AC5FD /* GCThread.cpp */; }; C2239D1B16262BDD005AC5FD /* GCThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C2239D1616262BDD005AC5FD /* GCThread.h */; }; C225494315F7DBAA0065E898 /* SlotVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C225494215F7DBAA0065E898 /* SlotVisitor.cpp */; }; @@ -728,7 +731,7 @@ C2A7F688160432D400F76B98 /* JSDestructibleObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C2A7F687160432D400F76B98 /* JSDestructibleObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = C2B916C114DA014E00CBAC86 /* MarkedAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2B916C514DA040C00CBAC86 /* MarkedAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2B916C414DA040C00CBAC86 /* MarkedAllocator.cpp */; }; - C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2C8D03014A3CEFC00578E65 /* CopiedBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02E14A3CEFC00578E65 /* CopiedBlock.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2C8D03114A3CEFC00578E65 /* HeapBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2D58C3415912FEE0021A844 /* GCActivityCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */; }; @@ -951,6 +954,9 @@ 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>"; }; 0F8023E91613832300A0BA45 /* ByValInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByValInfo.h; sourceTree = "<group>"; }; + 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBranchDirection.h; path = dfg/DFGBranchDirection.h; sourceTree = "<group>"; }; + 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayAllocationProfile.cpp; sourceTree = "<group>"; }; + 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayAllocationProfile.h; sourceTree = "<group>"; }; 0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSymbolTableObject.cpp; sourceTree = "<group>"; }; 0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSymbolTableObject.h; sourceTree = "<group>"; }; 0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSegmentedVariableObject.cpp; sourceTree = "<group>"; }; @@ -979,9 +985,9 @@ 0FB7F38915ED8E3800F167B2 /* ArrayConventions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayConventions.h; sourceTree = "<group>"; }; 0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayStorage.h; sourceTree = "<group>"; }; 0FB7F38B15ED8E3800F167B2 /* Butterfly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Butterfly.h; sourceTree = "<group>"; }; - 0FB7F38C15ED8E3800F167B2 /* ButterflyInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ButterflyInlineMethods.h; sourceTree = "<group>"; }; + 0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ButterflyInlines.h; sourceTree = "<group>"; }; 0FB7F38D15ED8E3800F167B2 /* IndexingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexingHeader.h; sourceTree = "<group>"; }; - 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexingHeaderInlineMethods.h; sourceTree = "<group>"; }; + 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexingHeaderInlines.h; sourceTree = "<group>"; }; 0FB7F38F15ED8E3800F167B2 /* IndexingType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexingType.h; sourceTree = "<group>"; }; 0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyStorage.h; sourceTree = "<group>"; }; 0FB7F39115ED8E3800F167B2 /* Reject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reject.h; sourceTree = "<group>"; }; @@ -1006,7 +1012,7 @@ 0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WriteBarrierSupport.h; sourceTree = "<group>"; }; 0FC815121405118600CFA603 /* VTableSpectrum.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VTableSpectrum.cpp; sourceTree = "<group>"; }; 0FC815141405118D00CFA603 /* VTableSpectrum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTableSpectrum.h; sourceTree = "<group>"; }; - 0FCB408515C0A3C30048932B /* SlotVisitorInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlotVisitorInlineMethods.h; sourceTree = "<group>"; }; + 0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlotVisitorInlines.h; sourceTree = "<group>"; }; 0FD3C82014115CF800FD81CB /* DFGDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDriver.cpp; path = dfg/DFGDriver.cpp; sourceTree = "<group>"; }; 0FD3C82214115D0E00FD81CB /* DFGDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDriver.h; path = dfg/DFGDriver.h; sourceTree = "<group>"; }; 0FD81ACF154FB4EB00983E72 /* DFGDominators.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDominators.cpp; path = dfg/DFGDominators.cpp; sourceTree = "<group>"; }; @@ -1226,7 +1232,7 @@ 863C6D981521111200585E4E /* YarrCanonicalizeUCS2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YarrCanonicalizeUCS2.cpp; path = yarr/YarrCanonicalizeUCS2.cpp; sourceTree = "<group>"; }; 863C6D991521111200585E4E /* YarrCanonicalizeUCS2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YarrCanonicalizeUCS2.h; path = yarr/YarrCanonicalizeUCS2.h; sourceTree = "<group>"; }; 863C6D9A1521111200585E4E /* YarrCanonicalizeUCS2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = YarrCanonicalizeUCS2.js; path = yarr/YarrCanonicalizeUCS2.js; sourceTree = "<group>"; }; - 865A30F0135007E100CDB49E /* JSValueInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueInlineMethods.h; sourceTree = "<group>"; }; + 865A30F0135007E100CDB49E /* JSValueInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueInlines.h; sourceTree = "<group>"; }; 865F408710E7D56300947361 /* APIShims.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIShims.h; sourceTree = "<group>"; }; 866739D013BFDE710023D87C /* BigInteger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BigInteger.h; sourceTree = "<group>"; }; 866739D113BFDE710023D87C /* Uint16WithFraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Uint16WithFraction.h; sourceTree = "<group>"; }; @@ -1268,7 +1274,7 @@ 86C568DF11A213EE0007F7F0 /* MIPSAssembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIPSAssembler.h; sourceTree = "<group>"; }; 86CA032D1038E8440028A609 /* Executable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Executable.cpp; sourceTree = "<group>"; }; 86CAFEE21035DDE60028A609 /* Executable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Executable.h; sourceTree = "<group>"; }; - 86CC85A00EE79A4700288682 /* JITInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITInlineMethods.h; sourceTree = "<group>"; }; + 86CC85A00EE79A4700288682 /* JITInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITInlines.h; sourceTree = "<group>"; }; 86CC85A20EE79B7400288682 /* JITCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITCall.cpp; sourceTree = "<group>"; }; 86CC85C30EE7A89400288682 /* JITPropertyAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITPropertyAccess.cpp; sourceTree = "<group>"; }; 86CCEFDD0F413F8900FD7F9E /* JITCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITCode.h; sourceTree = "<group>"; }; @@ -1501,10 +1507,10 @@ BCFD8C910EEB2EE700283848 /* JumpTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JumpTable.h; sourceTree = "<group>"; }; C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCThreadSharedData.cpp; sourceTree = "<group>"; }; C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCThreadSharedData.h; sourceTree = "<group>"; }; - C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStackInlineMethods.h; sourceTree = "<group>"; }; + C21122E015DD9AB300790E3A /* MarkStackInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStackInlines.h; sourceTree = "<group>"; }; C2239D1216262BDD005AC5FD /* CopyVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CopyVisitor.cpp; sourceTree = "<group>"; }; C2239D1316262BDD005AC5FD /* CopyVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyVisitor.h; sourceTree = "<group>"; }; - C2239D1416262BDD005AC5FD /* CopyVisitorInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyVisitorInlineMethods.h; sourceTree = "<group>"; }; + C2239D1416262BDD005AC5FD /* CopyVisitorInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyVisitorInlines.h; sourceTree = "<group>"; }; C2239D1516262BDD005AC5FD /* GCThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCThread.cpp; sourceTree = "<group>"; }; C2239D1616262BDD005AC5FD /* GCThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCThread.h; sourceTree = "<group>"; }; C225494215F7DBAA0065E898 /* SlotVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SlotVisitor.cpp; sourceTree = "<group>"; }; @@ -1516,7 +1522,7 @@ C2A7F687160432D400F76B98 /* JSDestructibleObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDestructibleObject.h; sourceTree = "<group>"; }; C2B916C114DA014E00CBAC86 /* MarkedAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkedAllocator.h; sourceTree = "<group>"; }; C2B916C414DA040C00CBAC86 /* MarkedAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MarkedAllocator.cpp; sourceTree = "<group>"; }; - C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedSpaceInlineMethods.h; sourceTree = "<group>"; }; + C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedSpaceInlines.h; sourceTree = "<group>"; }; C2C8D02E14A3CEFC00578E65 /* CopiedBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedBlock.h; sourceTree = "<group>"; }; C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapBlock.h; sourceTree = "<group>"; }; C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCActivityCallback.cpp; sourceTree = "<group>"; }; @@ -1816,7 +1822,7 @@ 0F21C26614BE5F5E00ADC64B /* JITDriver.h */, 0F46807F14BA572700BFE272 /* JITExceptions.cpp */, 0F46808014BA572700BFE272 /* JITExceptions.h */, - 86CC85A00EE79A4700288682 /* JITInlineMethods.h */, + 86CC85A00EE79A4700288682 /* JITInlines.h */, BCDD51E90FB8DF74004A8BDC /* JITOpcodes.cpp */, A71236E41195F33C00BD2174 /* JITOpcodes32_64.cpp */, 86CC85C30EE7A89400288682 /* JITPropertyAccess.cpp */, @@ -1842,7 +1848,7 @@ children = ( C2239D1216262BDD005AC5FD /* CopyVisitor.cpp */, C2239D1316262BDD005AC5FD /* CopyVisitor.h */, - C2239D1416262BDD005AC5FD /* CopyVisitorInlineMethods.h */, + C2239D1416262BDD005AC5FD /* CopyVisitorInlines.h */, C2239D1516262BDD005AC5FD /* GCThread.cpp */, C2239D1616262BDD005AC5FD /* GCThread.h */, C24D31E0161CD695002AA4DB /* HeapStatistics.cpp */, @@ -1850,7 +1856,7 @@ C225494215F7DBAA0065E898 /* SlotVisitor.cpp */, C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */, C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */, - C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */, + C21122E015DD9AB300790E3A /* MarkStackInlines.h */, C2E526BB1590EF000054E48D /* HeapTimer.cpp */, C2E526BC1590EF000054E48D /* HeapTimer.h */, C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */, @@ -1864,7 +1870,7 @@ C2C8D02E14A3CEFC00578E65 /* CopiedBlock.h */, C240305314B404C90079EB64 /* CopiedSpace.cpp */, C2EAA3F8149A830800FCE112 /* CopiedSpace.h */, - C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlineMethods.h */, + C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlines.h */, 0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */, 0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */, BCBE2CAD14E985AA000593AD /* GCAssertions.h */, @@ -1896,7 +1902,7 @@ 142D6F0F13539A4100B02E86 /* MarkStack.h */, 1497209014EB831500FEB1B7 /* PassWeak.h */, 14BA78F013AAB88F005B7C2C /* SlotVisitor.h */, - 0FCB408515C0A3C30048932B /* SlotVisitorInlineMethods.h */, + 0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */, 142E3132134FF0A600AFADB5 /* Strong.h */, 145722851437E140005FDE26 /* StrongInlines.h */, 141448CC13A1783700F5BA1A /* TinyBloomFilter.h */, @@ -2100,7 +2106,7 @@ BC7952340E15EB5600A898AB /* BooleanPrototype.cpp */, BC7952350E15EB5600A898AB /* BooleanPrototype.h */, 0FB7F38B15ED8E3800F167B2 /* Butterfly.h */, - 0FB7F38C15ED8E3800F167B2 /* ButterflyInlineMethods.h */, + 0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */, 869D04AE1193B54D00803475 /* CachedTranscendentalFunction.h */, BCA62DFE0E2826230004F30D /* CallData.cpp */, 145C507F0D9DF63B0088F6B9 /* CallData.h */, @@ -2146,7 +2152,7 @@ 933A349D038AE80F008635CE /* Identifier.cpp */, 933A349A038AE7C6008635CE /* Identifier.h */, 0FB7F38D15ED8E3800F167B2 /* IndexingHeader.h */, - 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlineMethods.h */, + 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlines.h */, 0F13E04C16164A1B00DC8DE7 /* IndexingType.cpp */, 0FB7F38F15ED8E3800F167B2 /* IndexingType.h */, E178636C0D9BEEC300D74E75 /* InitializeThreading.cpp */, @@ -2203,7 +2209,7 @@ 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */, F692A8870255597D01FF60F7 /* JSValue.cpp */, 14ABB36E099C076400E2A24F /* JSValue.h */, - 865A30F0135007E100CDB49E /* JSValueInlineMethods.h */, + 865A30F0135007E100CDB49E /* JSValueInlines.h */, BC22A39A0E16E14800AF21C8 /* JSVariableObject.cpp */, 14F252560D08DD8D004ECFFF /* JSVariableObject.h */, 1442565F15EDE98D0066A49B /* JSWithScope.cpp */, @@ -2362,6 +2368,7 @@ 0FC0976B1468AB4A00CF2442 /* DFGAssemblyHelpers.cpp */, 0FC0976C1468AB4A00CF2442 /* DFGAssemblyHelpers.h */, 0F620170143FCD2F0068B77C /* DFGBasicBlock.h */, + 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */, 0F5F08CC146BE602000472A9 /* DFGByteCodeCache.h */, 86EC9DB41328DF82002B2AD7 /* DFGByteCodeParser.cpp */, 86EC9DB51328DF82002B2AD7 /* DFGByteCodeParser.h */, @@ -2515,6 +2522,8 @@ 969A078F0ED1D3AE00F1F681 /* bytecode */ = { isa = PBXGroup; children = ( + 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */, + 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */, 0F63945115D07051006A597C /* ArrayProfile.cpp */, 0F63945215D07051006A597C /* ArrayProfile.h */, 0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */, @@ -2616,14 +2625,14 @@ C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */, FE4A332015BD2E07006F54F3 /* VMInspector.h in Headers */, C2239D1816262BDD005AC5FD /* CopyVisitor.h in Headers */, - C2239D1916262BDD005AC5FD /* CopyVisitorInlineMethods.h in Headers */, + C2239D1916262BDD005AC5FD /* CopyVisitorInlines.h in Headers */, C24D31E3161CD695002AA4DB /* HeapStatistics.h in Headers */, C2A7F688160432D400F76B98 /* JSDestructibleObject.h in Headers */, FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */, C21122E215DD9AB300790E3A /* GCThreadSharedData.h in Headers */, - C2160FE715F7E95E00942DFC /* SlotVisitorInlineMethods.h in Headers */, + C2160FE715F7E95E00942DFC /* SlotVisitorInlines.h in Headers */, C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */, - C21122E315DD9AB300790E3A /* MarkStackInlineMethods.h in Headers */, + C21122E315DD9AB300790E3A /* MarkStackInlines.h in Headers */, C25F8BCE157544A900245B71 /* IncrementalSweeper.h in Headers */, BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */, BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */, @@ -2636,7 +2645,7 @@ BC18C3EC0E16F5CD00B34460 /* BooleanObject.h in Headers */, C2C8D03014A3CEFC00578E65 /* CopiedBlock.h in Headers */, C2EAA3FA149A835E00FCE112 /* CopiedSpace.h in Headers */, - C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlineMethods.h in Headers */, + C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlines.h in Headers */, 969A07230ED1CE3300F1F681 /* BytecodeGenerator.h in Headers */, 869D04AF1193B54D00803475 /* CachedTranscendentalFunction.h in Headers */, BC18C3ED0E16F5CD00B34460 /* CallData.h in Headers */, @@ -2718,7 +2727,7 @@ BC18C4150E16F5CD00B34460 /* JavaScriptCorePrefix.h in Headers */, 1429D9300ED22D7000B89619 /* JIT.h in Headers */, 86CCEFDE0F413F8900FD7F9E /* JITCode.h in Headers */, - 86CC85A10EE79A4700288682 /* JITInlineMethods.h in Headers */, + 86CC85A10EE79A4700288682 /* JITInlines.h in Headers */, 960626960FB8EC02009798AB /* JITStubCall.h in Headers */, 14C5242B0F5355E900BA3D04 /* JITStubs.h in Headers */, A76F54A313B28AAB00EF2BCE /* JITWriteBarrier.h in Headers */, @@ -2760,7 +2769,7 @@ BC18C42A0E16F5CD00B34460 /* JSType.h in Headers */, 6507D29E0E871E5E00D7D896 /* JSTypeInfo.h in Headers */, BC18C42B0E16F5CD00B34460 /* JSValue.h in Headers */, - 865A30F1135007E100CDB49E /* JSValueInlineMethods.h in Headers */, + 865A30F1135007E100CDB49E /* JSValueInlines.h in Headers */, BC18C42C0E16F5CD00B34460 /* JSValueRef.h in Headers */, BC18C42D0E16F5CD00B34460 /* JSVariableObject.h in Headers */, A7482E93116A7CAD003B0712 /* JSWeakObjectMapRefInternal.h in Headers */, @@ -2994,9 +3003,9 @@ 0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */, 0FB7F39615ED8E4600F167B2 /* ArrayStorage.h in Headers */, 0FB7F39715ED8E4600F167B2 /* Butterfly.h in Headers */, - 0FB7F39815ED8E4600F167B2 /* ButterflyInlineMethods.h in Headers */, + 0FB7F39815ED8E4600F167B2 /* ButterflyInlines.h in Headers */, 0FB7F39915ED8E4600F167B2 /* IndexingHeader.h in Headers */, - 0FB7F39A15ED8E4600F167B2 /* IndexingHeaderInlineMethods.h in Headers */, + 0FB7F39A15ED8E4600F167B2 /* IndexingHeaderInlines.h in Headers */, 0FB7F39B15ED8E4600F167B2 /* IndexingType.h in Headers */, 0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */, 0FB7F39D15ED8E4600F167B2 /* Reject.h in Headers */, @@ -3008,6 +3017,8 @@ 0FEB3ECD16237F4D00AB67AD /* TypedArrayDescriptor.h in Headers */, 0F256C361627B0AD007F2783 /* DFGCallArrayAllocatorSlowPathGenerator.h in Headers */, C2239D1B16262BDD005AC5FD /* GCThread.h in Headers */, + 0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */, + 0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */, A7B601821639FD2A00372BA3 /* UnlinkedCodeBlock.h in Headers */, A77F1822164088B200640A47 /* CodeCache.h in Headers */, A77F1825164192C700640A47 /* ParserModes.h in Headers */, @@ -3587,6 +3598,7 @@ C24D31E2161CD695002AA4DB /* HeapStatistics.cpp in Sources */, C2239D1716262BDD005AC5FD /* CopyVisitor.cpp in Sources */, C2239D1A16262BDD005AC5FD /* GCThread.cpp in Sources */, + 0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */, A76F279415F13C9600517D67 /* UnlinkedCodeBlock.cpp in Sources */, A77F1821164088B200640A47 /* CodeCache.cpp in Sources */, ); diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri index b0fcc16e7..f978fb46b 100644 --- a/Source/JavaScriptCore/Target.pri +++ b/Source/JavaScriptCore/Target.pri @@ -50,6 +50,7 @@ SOURCES += \ assembler/MacroAssembler.cpp \ assembler/MacroAssemblerARM.cpp \ assembler/MacroAssemblerSH4.cpp \ + bytecode/ArrayAllocationProfile.cpp \ bytecode/ArrayProfile.cpp \ bytecode/CallLinkInfo.cpp \ bytecode/CallLinkStatus.cpp \ diff --git a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h index c75adb7e9..673031b7a 100644 --- a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h +++ b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h @@ -586,6 +586,13 @@ public: public: typedef Vector<Jump, 16> JumpVector; + + JumpList() { } + + JumpList(Jump jump) + { + append(jump); + } void link(AbstractMacroAssembler<AssemblerType>* masm) { diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h index 66db26acb..53cb80c21 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h @@ -826,11 +826,15 @@ public: m_assembler.ucomisd_rr(right, left); if (cond == DoubleEqual) { + if (left == right) + return Jump(m_assembler.jnp()); Jump isUnordered(m_assembler.jp()); Jump result = Jump(m_assembler.je()); isUnordered.link(this); return result; } else if (cond == DoubleNotEqualOrUnordered) { + if (left == right) + return Jump(m_assembler.jp()); Jump isUnordered(m_assembler.jp()); Jump isEqual(m_assembler.je()); isUnordered.link(this); diff --git a/Source/JavaScriptCore/assembler/X86Assembler.h b/Source/JavaScriptCore/assembler/X86Assembler.h index ecb178e88..4d08b70ce 100644 --- a/Source/JavaScriptCore/assembler/X86Assembler.h +++ b/Source/JavaScriptCore/assembler/X86Assembler.h @@ -1475,6 +1475,12 @@ public: return m_formatter.immediateRel32(); } + AssemblerLabel jnp() + { + m_formatter.twoByteOp(jccRel32(ConditionNP)); + return m_formatter.immediateRel32(); + } + AssemblerLabel jp() { m_formatter.twoByteOp(jccRel32(ConditionP)); @@ -2314,6 +2320,9 @@ private: // Format a REX prefix byte. inline void emitRex(bool w, int r, int x, int b) { + ASSERT(r >= 0); + ASSERT(x >= 0); + ASSERT(b >= 0); m_buffer.putByteUnchecked(PRE_REX | ((int)w << 3) | ((r>>3)<<2) | ((x>>3)<<1) | (b>>3)); } diff --git a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp new file mode 100644 index 000000000..aa682da86 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp @@ -0,0 +1,40 @@ +/* + * 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 "ArrayAllocationProfile.h" + +namespace JSC { + +void ArrayAllocationProfile::updateIndexingType() +{ + if (!m_lastArray) + return; + m_currentIndexingType = leastUpperBoundOfIndexingTypes(m_currentIndexingType, m_lastArray->structure()->indexingType()); + m_lastArray = 0; +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h new file mode 100644 index 000000000..a1647fad4 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h @@ -0,0 +1,80 @@ +/* + * 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 ArrayAllocationProfile_h +#define ArrayAllocationProfile_h + +#include "IndexingType.h" +#include "JSArray.h" + +namespace JSC { + +class ArrayAllocationProfile { +public: + ArrayAllocationProfile() + : m_currentIndexingType(ArrayWithUndecided) + , m_lastArray(0) + { + } + + IndexingType selectIndexingType() + { + if (m_lastArray && UNLIKELY(m_lastArray->structure()->indexingType() != m_currentIndexingType)) + updateIndexingType(); + return m_currentIndexingType; + } + + JSArray* updateLastAllocation(JSArray* lastArray) + { + m_lastArray = lastArray; + return lastArray; + } + + JS_EXPORT_PRIVATE void updateIndexingType(); + + static IndexingType selectIndexingTypeFor(ArrayAllocationProfile* profile) + { + if (!profile) + return ArrayWithUndecided; + return profile->selectIndexingType(); + } + + static JSArray* updateLastAllocationFor(ArrayAllocationProfile* profile, JSArray* lastArray) + { + if (profile) + profile->updateLastAllocation(lastArray); + return lastArray; + } + +private: + + IndexingType m_currentIndexingType; + JSArray* m_lastArray; +}; + +} // namespace JSC + +#endif // ArrayAllocationProfile_h + diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp index 5a87380fd..51baf332f 100644 --- a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp +++ b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp @@ -65,6 +65,13 @@ const char* arrayModesToString(ArrayModes arrayModes) return result; } +ArrayModes ArrayProfile::updatedObservedArrayModes() const +{ + if (m_lastSeenStructure) + return m_observedArrayModes | arrayModeFromStructure(m_lastSeenStructure); + return m_observedArrayModes; +} + void ArrayProfile::computeUpdatedPrediction(CodeBlock* codeBlock, OperationInProgress operation) { if (m_lastSeenStructure) { diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.h b/Source/JavaScriptCore/bytecode/ArrayProfile.h index 376684fc1..5116cd36f 100644 --- a/Source/JavaScriptCore/bytecode/ArrayProfile.h +++ b/Source/JavaScriptCore/bytecode/ArrayProfile.h @@ -45,15 +45,20 @@ typedef unsigned ArrayModes; #define ALL_NON_ARRAY_ARRAY_MODES \ (asArrayModes(NonArray) \ - | asArrayModes(NonArrayWithContiguous) \ - | asArrayModes(NonArrayWithArrayStorage) \ - | asArrayModes(NonArrayWithSlowPutArrayStorage)) + | asArrayModes(NonArrayWithInt32) \ + | asArrayModes(NonArrayWithDouble) \ + | asArrayModes(NonArrayWithContiguous) \ + | asArrayModes(NonArrayWithArrayStorage) \ + | asArrayModes(NonArrayWithSlowPutArrayStorage)) #define ALL_ARRAY_ARRAY_MODES \ (asArrayModes(ArrayClass) \ - | asArrayModes(ArrayWithContiguous) \ - | asArrayModes(ArrayWithArrayStorage) \ - | asArrayModes(ArrayWithSlowPutArrayStorage)) + | asArrayModes(ArrayWithUndecided) \ + | asArrayModes(ArrayWithInt32) \ + | asArrayModes(ArrayWithDouble) \ + | asArrayModes(ArrayWithContiguous) \ + | asArrayModes(ArrayWithArrayStorage) \ + | asArrayModes(ArrayWithSlowPutArrayStorage)) #define ALL_ARRAY_MODES (ALL_NON_ARRAY_ARRAY_MODES | ALL_ARRAY_ARRAY_MODES) @@ -79,6 +84,36 @@ inline bool arrayModesAlreadyChecked(ArrayModes proven, ArrayModes expected) return (expected | proven) == expected; } +inline bool arrayModesInclude(ArrayModes arrayModes, IndexingType shape) +{ + return !!(arrayModes & (asArrayModes(NonArray | shape) | asArrayModes(ArrayClass | shape))); +} + +inline bool shouldUseSlowPutArrayStorage(ArrayModes arrayModes) +{ + return arrayModesInclude(arrayModes, SlowPutArrayStorageShape); +} + +inline bool shouldUseFastArrayStorage(ArrayModes arrayModes) +{ + return arrayModesInclude(arrayModes, ArrayStorageShape); +} + +inline bool shouldUseContiguous(ArrayModes arrayModes) +{ + return arrayModesInclude(arrayModes, ContiguousShape); +} + +inline bool shouldUseDouble(ArrayModes arrayModes) +{ + return arrayModesInclude(arrayModes, DoubleShape); +} + +inline bool shouldUseInt32(ArrayModes arrayModes) +{ + return arrayModesInclude(arrayModes, Int32Shape); +} + class ArrayProfile { public: ArrayProfile() @@ -128,6 +163,7 @@ public: return !structureIsPolymorphic() && m_expectedStructure; } ArrayModes observedArrayModes() const { return m_observedArrayModes; } + ArrayModes updatedObservedArrayModes() const; // Computes the observed array modes without updating the profile. bool mayInterceptIndexedAccesses() const { return m_mayInterceptIndexedAccesses; } bool mayStoreToHole() const { return m_mayStoreToHole; } diff --git a/Source/JavaScriptCore/bytecode/ByValInfo.h b/Source/JavaScriptCore/bytecode/ByValInfo.h index 8cba4463d..3f79967df 100644 --- a/Source/JavaScriptCore/bytecode/ByValInfo.h +++ b/Source/JavaScriptCore/bytecode/ByValInfo.h @@ -39,6 +39,8 @@ namespace JSC { enum JITArrayMode { + JITInt32, + JITDouble, JITContiguous, JITArrayStorage, JITInt8Array, @@ -55,6 +57,8 @@ enum JITArrayMode { inline bool isOptimizableIndexingType(IndexingType indexingType) { switch (indexingType) { + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: return true; @@ -77,6 +81,10 @@ inline bool hasOptimizableIndexing(Structure* structure) inline JITArrayMode jitArrayModeForIndexingType(IndexingType indexingType) { switch (indexingType) { + case ALL_INT32_INDEXING_TYPES: + return JITInt32; + case ALL_DOUBLE_INDEXING_TYPES: + return JITDouble; case ALL_CONTIGUOUS_INDEXING_TYPES: return JITContiguous; case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index ceae3fcb2..83833c6ec 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -44,7 +44,7 @@ #include "JSValue.h" #include "LowLevelInterpreter.h" #include "RepatchBuffer.h" -#include "SlotVisitorInlineMethods.h" +#include "SlotVisitorInlines.h" #include <stdio.h> #include <wtf/StringExtras.h> #include <wtf/UnusedParam.h> @@ -654,6 +654,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int argc = (++it)->u.operand; dataLog("[%4d] new_array\t %s, %s, %d", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc); dumpBytecodeCommentAndNewLine(location); + ++it; // Skip array allocation profile. break; } case op_new_array_with_size: { @@ -661,6 +662,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int length = (++it)->u.operand; dataLog("[%4d] new_array_with_size\t %s, %s", location, registerName(exec, dst).data(), registerName(exec, length).data()); dumpBytecodeCommentAndNewLine(location); + ++it; // Skip array allocation profile. break; } case op_new_array_buffer: { @@ -669,6 +671,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int argc = (++it)->u.operand; dataLog("[%4d] new_array_buffer\t %s, %d, %d", location, registerName(exec, dst).data(), argv, argc); dumpBytecodeCommentAndNewLine(location); + ++it; // Skip array allocation profile. break; } case op_new_regexp: { @@ -1746,6 +1749,8 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin #if ENABLE(DFG_JIT) if (size_t size = unlinkedCodeBlock->numberOfArrayProfiles()) m_arrayProfiles.grow(size); + if (size_t size = unlinkedCodeBlock->numberOfArrayAllocationProfiles()) + m_arrayAllocationProfiles.grow(size); if (size_t size = unlinkedCodeBlock->numberOfValueProfiles()) m_valueProfiles.grow(size); #endif @@ -1800,19 +1805,32 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin break; } + case op_new_array: + case op_new_array_buffer: + case op_new_array_with_size: { + int arrayAllocationProfileIndex = pc[i + opLength - 1].u.operand; + instructions[i + opLength - 1] = &m_arrayAllocationProfiles[arrayAllocationProfileIndex]; + break; + } +#endif + case op_call: case op_call_eval: { +#if ENABLE(DFG_JIT) int arrayProfileIndex = pc[i + opLength - 1].u.operand; m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i); instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex]; - // fallthrough - } #endif #if ENABLE(LLINT) - case op_construct: instructions[i + 4] = &m_llintCallLinkInfos[pc[i + 4].u.operand]; +#endif break; + } + case op_construct: +#if ENABLE(LLINT) + instructions[i + 4] = &m_llintCallLinkInfos[pc[i + 4].u.operand]; #endif + break; case op_get_by_id_out_of_line: case op_get_by_id_self: case op_get_by_id_proto: @@ -2787,18 +2805,28 @@ void CodeBlock::updateAllPredictionsAndCountLiveness( #if ENABLE(DFG_JIT) m_lazyOperandValueProfiles.computeUpdatedPredictions(operation); #endif - - // Don't count the array profiles towards statistics, since each array profile - // site also has a value profile site - so we already know whether or not it's - // live. +} + +void CodeBlock::updateAllValueProfilePredictions(OperationInProgress operation) +{ + unsigned ignoredValue1, ignoredValue2; + updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2); +} + +void CodeBlock::updateAllArrayPredictions(OperationInProgress operation) +{ for (unsigned i = m_arrayProfiles.size(); i--;) m_arrayProfiles[i].computeUpdatedPrediction(this, operation); + + // Don't count these either, for similar reasons. + for (unsigned i = m_arrayAllocationProfiles.size(); i--;) + m_arrayAllocationProfiles[i].updateIndexingType(); } void CodeBlock::updateAllPredictions(OperationInProgress operation) { - unsigned ignoredValue1, ignoredValue2; - updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2); + updateAllValueProfilePredictions(operation); + updateAllArrayPredictions(operation); } bool CodeBlock::shouldOptimizeNow() @@ -2814,12 +2842,14 @@ bool CodeBlock::shouldOptimizeNow() if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay()) return true; + updateAllArrayPredictions(); + unsigned numberOfLiveNonArgumentValueProfiles; unsigned numberOfSamplesInProfiles; updateAllPredictionsAndCountLiveness(NoOperation, numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles); #if ENABLE(JIT_VERBOSE_OSR) - dataLog("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles()); + dataLog("Profile hotness: %lf (%u / %u), %lf (%u / %u)\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), numberOfLiveNonArgumentValueProfiles, numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles(), numberOfSamplesInProfiles, ValueProfile::numberOfBuckets * numberOfValueProfiles()); #endif if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles() >= Options::desiredProfileLivenessRate()) diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index a28064940..0199935bb 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -755,6 +755,13 @@ namespace JSC { } ArrayProfile* getArrayProfile(unsigned bytecodeOffset); ArrayProfile* getOrAddArrayProfile(unsigned bytecodeOffset); + + unsigned numberOfArrayAllocationProfiles() const { return m_arrayAllocationProfiles.size(); } + ArrayAllocationProfile* addArrayAllocationProfile() + { + m_arrayAllocationProfiles.append(ArrayAllocationProfile()); + return &m_arrayAllocationProfiles.last(); + } #endif // Exception handling support @@ -1145,9 +1152,13 @@ namespace JSC { #if ENABLE(VALUE_PROFILER) bool shouldOptimizeNow(); + void updateAllValueProfilePredictions(OperationInProgress = NoOperation); + void updateAllArrayPredictions(OperationInProgress = NoOperation); void updateAllPredictions(OperationInProgress = NoOperation); #else bool shouldOptimizeNow() { return false; } + void updateAllValueProfilePredictions(OperationInProgress = NoOperation) { } + void updateAllArrayPredictions(OperationInProgress = NoOperation) { } void updateAllPredictions(OperationInProgress = NoOperation) { } #endif @@ -1330,6 +1341,7 @@ namespace JSC { SegmentedVector<ValueProfile, 8> m_valueProfiles; SegmentedVector<RareCaseProfile, 8> m_rareCaseProfiles; SegmentedVector<RareCaseProfile, 8> m_specialFastCaseProfiles; + SegmentedVector<ArrayAllocationProfile, 8> m_arrayAllocationProfiles; ArrayProfileVector m_arrayProfiles; unsigned m_executionEntryCount; #endif diff --git a/Source/JavaScriptCore/bytecode/DFGExitProfile.h b/Source/JavaScriptCore/bytecode/DFGExitProfile.h index 60d313ad4..7132adfd4 100644 --- a/Source/JavaScriptCore/bytecode/DFGExitProfile.h +++ b/Source/JavaScriptCore/bytecode/DFGExitProfile.h @@ -58,6 +58,8 @@ inline const char* exitKindToString(ExitKind kind) return "BadCache"; case BadWeakConstantCache: return "BadWeakConstantCache"; + case BadIndexingType: + return "BadIndexingType"; case Overflow: return "Overflow"; case NegativeZero: diff --git a/Source/JavaScriptCore/bytecode/Instruction.h b/Source/JavaScriptCore/bytecode/Instruction.h index 9fcf509f6..50b80e03c 100644 --- a/Source/JavaScriptCore/bytecode/Instruction.h +++ b/Source/JavaScriptCore/bytecode/Instruction.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 @@ -47,6 +47,7 @@ namespace JSC { // curently actually use PolymorphicAccessStructureLists, which we should). Anyway, this seems like the best // solution for now - will need to something smarter if/when we actually want mixed-mode operation. + class ArrayAllocationProfile; class ArrayProfile; class JSCell; class Structure; @@ -193,6 +194,7 @@ namespace JSC { Instruction(ValueProfile* profile) { u.profile = profile; } Instruction(ArrayProfile* profile) { u.arrayProfile = profile; } + Instruction(ArrayAllocationProfile* profile) { u.arrayAllocationProfile = profile; } Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; } @@ -212,6 +214,7 @@ namespace JSC { LLIntCallLinkInfo* callLinkInfo; ValueProfile* profile; ArrayProfile* arrayProfile; + ArrayAllocationProfile* arrayAllocationProfile; void* pointer; bool* predicatePointer; } u; diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index 8979d0b7b..38d314d78 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -48,9 +48,9 @@ namespace JSC { macro(op_convert_this, 3) \ \ macro(op_new_object, 2) \ - macro(op_new_array, 4) \ - macro(op_new_array_with_size, 3) \ - macro(op_new_array_buffer, 4) \ + macro(op_new_array, 5) \ + macro(op_new_array_with_size, 4) \ + macro(op_new_array_buffer, 5) \ macro(op_new_regexp, 3) \ macro(op_mov, 3) \ \ diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h index 09ba9fdfa..656bc79ee 100644 --- a/Source/JavaScriptCore/bytecode/SpeculatedType.h +++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h @@ -61,6 +61,7 @@ static const SpeculatedType SpecInt32 = 0x00800000; // It's definite static const SpeculatedType SpecDoubleReal = 0x01000000; // It's definitely a non-NaN double. static const SpeculatedType SpecDoubleNaN = 0x02000000; // It's definitely a NaN. static const SpeculatedType SpecDouble = 0x03000000; // It's either a non-NaN or a NaN double. +static const SpeculatedType SpecRealNumber = 0x01800000; // It's either an Int32 or a DoubleReal. static const SpeculatedType SpecNumber = 0x03800000; // It's either an Int32 or a Double. static const SpeculatedType SpecBoolean = 0x04000000; // It's definitely a Boolean. static const SpeculatedType SpecOther = 0x08000000; // It's definitely none of the above. @@ -228,6 +229,16 @@ inline bool isInt32Speculation(SpeculatedType value) return value == SpecInt32; } +inline bool isInt32SpeculationForArithmetic(SpeculatedType value) +{ + return !(value & SpecDouble); +} + +inline bool isInt32SpeculationExpectingDefined(SpeculatedType value) +{ + return isInt32Speculation(value & ~SpecOther); +} + inline bool isDoubleRealSpeculation(SpeculatedType value) { return value == SpecDoubleReal; @@ -238,11 +249,26 @@ inline bool isDoubleSpeculation(SpeculatedType value) return !!value && (value & SpecDouble) == value; } +inline bool isDoubleSpeculationForArithmetic(SpeculatedType value) +{ + return !!(value & SpecDouble); +} + +inline bool isRealNumberSpeculation(SpeculatedType value) +{ + return !!(value & SpecRealNumber) && !(value & ~SpecRealNumber); +} + inline bool isNumberSpeculation(SpeculatedType value) { return !!(value & SpecNumber) && !(value & ~SpecNumber); } +inline bool isNumberSpeculationExpectingDefined(SpeculatedType value) +{ + return isNumberSpeculation(value & ~SpecOther); +} + inline bool isBooleanSpeculation(SpeculatedType value) { return value == SpecBoolean; diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp index 8aa48404a..e98d4de0a 100644 --- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp @@ -80,8 +80,6 @@ void UnlinkedFunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visito COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); Base::visitChildren(thisObject, visitor); - visitor.append(&thisObject->m_codeBlockForCall); - visitor.append(&thisObject->m_codeBlockForConstruct); visitor.append(&thisObject->m_nameValue); visitor.append(&thisObject->m_symbolTableForCall); visitor.append(&thisObject->m_symbolTableForConstruct); @@ -112,12 +110,16 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData { switch (specializationKind) { case CodeForCall: - if (m_codeBlockForCall) - return m_codeBlockForCall.get(); + if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForCall.get()) { + globalData.codeCache()->usedFunctionCode(globalData, codeBlock); + return codeBlock; + } break; case CodeForConstruct: - if (m_codeBlockForConstruct) - return m_codeBlockForConstruct.get(); + if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForConstruct.get()) { + globalData.codeCache()->usedFunctionCode(globalData, codeBlock); + return codeBlock; + } break; } @@ -128,11 +130,11 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData switch (specializationKind) { case CodeForCall: - m_codeBlockForCall.set(globalData, this, result); + m_codeBlockForCall = PassWeak<UnlinkedFunctionCodeBlock>(result); m_symbolTableForCall.set(globalData, this, result->symbolTable()); break; case CodeForConstruct: - m_codeBlockForConstruct.set(globalData, this, result); + m_codeBlockForConstruct = PassWeak<UnlinkedFunctionCodeBlock>(result); m_symbolTableForConstruct.set(globalData, this, result->symbolTable()); break; } @@ -171,6 +173,7 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(JSGlobalData* globalData, Structure* struct , m_resolveOperationCount(0) , m_putToBaseOperationCount(1) , m_arrayProfileCount(0) + , m_arrayAllocationProfileCount(0) , m_valueProfileCount(0) , m_llintCallLinkInfoCount(0) #if ENABLE(BYTECODE_COMMENTS) diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h index bf3f5fdff..23937d773 100644 --- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h +++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h @@ -36,6 +36,7 @@ #include "Nodes.h" #include "RegExp.h" #include "SpecialPointer.h" +#include "Weak.h" #include <wtf/RefCountedArray.h> #include <wtf/Vector.h> @@ -56,6 +57,7 @@ class UnlinkedFunctionCodeBlock; typedef unsigned UnlinkedValueProfile; typedef unsigned UnlinkedArrayProfile; +typedef unsigned UnlinkedArrayAllocationProfile; typedef unsigned UnlinkedLLIntCallLinkInfo; struct ExecutableInfo { @@ -107,7 +109,7 @@ public: FunctionExecutable* link(JSGlobalData&, const SourceCode&, size_t lineOffset, size_t sourceOffset); - void clearCode() + void clearCodeForRecompilation() { m_symbolTableForCall.clear(); m_symbolTableForConstruct.clear(); @@ -135,8 +137,8 @@ public: private: UnlinkedFunctionExecutable(JSGlobalData*, Structure*, const SourceCode&, FunctionBodyNode*); - WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForCall; - WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct; + Weak<UnlinkedFunctionCodeBlock> m_codeBlockForCall; + Weak<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct; unsigned m_numCapturedVariables : 29; bool m_forceUsesArguments : 1; @@ -392,6 +394,8 @@ public: UnlinkedArrayProfile addArrayProfile() { return m_arrayProfileCount++; } unsigned numberOfArrayProfiles() { return m_arrayProfileCount; } + UnlinkedArrayAllocationProfile addArrayAllocationProfile() { return m_arrayAllocationProfileCount++; } + unsigned numberOfArrayAllocationProfiles() { return m_arrayAllocationProfileCount; } UnlinkedValueProfile addValueProfile() { return m_valueProfileCount++; } unsigned numberOfValueProfiles() { return m_valueProfileCount; } @@ -518,6 +522,7 @@ private: unsigned m_resolveOperationCount; unsigned m_putToBaseOperationCount; unsigned m_arrayProfileCount; + unsigned m_arrayAllocationProfileCount; unsigned m_valueProfileCount; unsigned m_llintCallLinkInfoCount; diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index b11872551..b1b9de6c1 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -716,6 +716,15 @@ UnlinkedArrayProfile BytecodeGenerator::newArrayProfile() #endif } +UnlinkedArrayAllocationProfile BytecodeGenerator::newArrayAllocationProfile() +{ +#if ENABLE(VALUE_PROFILER) + return m_codeBlock->addArrayAllocationProfile(); +#else + return 0; +#endif +} + UnlinkedValueProfile BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID) { #if ENABLE(VALUE_PROFILER) @@ -1605,6 +1614,7 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen instructions().append(dst->index()); instructions().append(constantBufferIndex); instructions().append(length); + instructions().append(newArrayAllocationProfile()); return dst; } } @@ -1622,6 +1632,7 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen instructions().append(dst->index()); instructions().append(argv.size() ? argv[0]->index() : 0); // argv instructions().append(argv.size()); // argc + instructions().append(newArrayAllocationProfile()); return dst; } @@ -1757,12 +1768,14 @@ ExpectedFunction BytecodeGenerator::emitExpectedFunctionSnippet(RegisterID* dst, emitOpcode(op_new_array_with_size); instructions().append(dst->index()); instructions().append(callArguments.argumentRegister(0)->index()); + instructions().append(newArrayAllocationProfile()); } else { ASSERT(callArguments.argumentCountIncludingThis() == 1); emitOpcode(op_new_array); instructions().append(dst->index()); instructions().append(0); instructions().append(0); + instructions().append(newArrayAllocationProfile()); } } break; diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h index 828726dee..2e7aa2035 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -523,6 +523,7 @@ namespace JSC { #endif void emitOpcode(OpcodeID); + UnlinkedArrayAllocationProfile newArrayAllocationProfile(); UnlinkedArrayProfile newArrayProfile(); UnlinkedValueProfile emitProfiledOpcode(OpcodeID); void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); diff --git a/Source/JavaScriptCore/debugger/Debugger.cpp b/Source/JavaScriptCore/debugger/Debugger.cpp index b14729146..7eda52dc8 100644 --- a/Source/JavaScriptCore/debugger/Debugger.cpp +++ b/Source/JavaScriptCore/debugger/Debugger.cpp @@ -80,7 +80,7 @@ inline void Recompiler::operator()(JSCell* cell) ExecState* exec = function->scope()->globalObject()->JSGlobalObject::globalExec(); executable->clearCodeIfNotCompiling(); - executable->clearUnlinkedCodeIfNotCompiling(); + executable->clearUnlinkedCodeForRecompilationIfNotCompiling(); if (m_debugger == function->scope()->globalObject()->debugger()) m_sourceProviders.add(executable->source().provider(), exec); } diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index e518c24a8..02e578b29 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -159,7 +159,7 @@ void AbstractState::initialize(Graph& graph) } } -bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDirectionPtr) +bool AbstractState::endBasicBlock(MergeMode mergeMode) { ASSERT(m_block); @@ -167,6 +167,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi block->cfaFoundConstants = m_foundConstants; block->cfaDidFinish = m_isValid; + block->cfaBranchDirection = m_branchDirection; if (!m_isValid) { reset(); @@ -195,12 +196,8 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi ASSERT(mergeMode != DontMerge || !changed); - BranchDirection branchDirection = m_branchDirection; - if (branchDirectionPtr) - *branchDirectionPtr = branchDirection; - #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog(" Branch direction = %s\n", branchDirectionToString(branchDirection)); + dataLog(" Branch direction = %s\n", branchDirectionToString(m_branchDirection)); #endif reset(); @@ -208,7 +205,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi if (mergeMode != MergeToSuccessors) return changed; - return mergeToSuccessors(m_graph, block, branchDirection); + return mergeToSuccessors(m_graph, block); } void AbstractState::reset() @@ -424,7 +421,10 @@ bool AbstractState::execute(unsigned indexInBlock) break; } speculateNumberUnary(node); - forNode(nodeIndex).set(SpecDouble); + if (isInt32Speculation(forNode(node.child1()).m_type)) + forNode(nodeIndex).set(SpecDoubleReal); + else + forNode(nodeIndex).set(SpecDouble); break; } @@ -448,9 +448,13 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(nodeIndex).set(SpecInt32); break; } - if (Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()])) { + if (Node::shouldSpeculateNumberExpectingDefined(m_graph[node.child1()], m_graph[node.child2()])) { speculateNumberBinary(node); - forNode(nodeIndex).set(SpecDouble); + if (isRealNumberSpeculation(forNode(node.child1()).m_type) + && isRealNumberSpeculation(forNode(node.child2()).m_type)) + forNode(nodeIndex).set(SpecDoubleReal); + else + forNode(nodeIndex).set(SpecDouble); break; } if (node.op() == ValueAdd) { @@ -522,7 +526,11 @@ bool AbstractState::execute(unsigned indexInBlock) break; } speculateNumberBinary(node); - forNode(nodeIndex).set(SpecDouble); + if (isRealNumberSpeculation(forNode(node.child1()).m_type) + || isRealNumberSpeculation(forNode(node.child2()).m_type)) + forNode(nodeIndex).set(SpecDoubleReal); + else + forNode(nodeIndex).set(SpecDouble); break; } @@ -560,7 +568,7 @@ bool AbstractState::execute(unsigned indexInBlock) break; } } - if (Node::shouldSpeculateInteger( + if (Node::shouldSpeculateIntegerForArithmetic( m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) { speculateInt32Binary(node, true); // forcing can-exit, which is a bit on the conservative side. @@ -580,7 +588,7 @@ bool AbstractState::execute(unsigned indexInBlock) node.setCanExit(false); break; } - if (m_graph[node.child1()].shouldSpeculateInteger() + if (m_graph[node.child1()].shouldSpeculateIntegerForArithmetic() && node.canSpeculateInteger()) { speculateInt32Unary(node, true); forNode(nodeIndex).set(SpecInt32); @@ -605,12 +613,22 @@ bool AbstractState::execute(unsigned indexInBlock) } case LogicalNot: { + // First check if we can fold because the source is a constant. JSValue childConst = forNode(node.child1()).value(); if (childConst && trySetConstant(nodeIndex, jsBoolean(!childConst.toBoolean(m_codeBlock->globalObjectFor(node.codeOrigin)->globalExec())))) { m_foundConstants = true; node.setCanExit(false); break; } + // Next check if we can fold because we know that the source is an object or string and does not equal undefined. + if (isCellSpeculation(forNode(node.child1()).m_type) + && forNode(node.child1()).m_currentKnownStructure.hasSingleton() + && !forNode(node.child1()).m_currentKnownStructure.singleton()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node.codeOrigin)) + && trySetConstant(nodeIndex, jsBoolean(false))) { + m_foundConstants = true; + node.setCanExit(false); + break; + } Node& child = m_graph[node.child1()]; if (isBooleanSpeculation(child.prediction())) speculateBooleanUnary(node); @@ -678,12 +696,13 @@ bool AbstractState::execute(unsigned indexInBlock) case CompareGreater: case CompareGreaterEq: case CompareEq: { + bool constantWasSet = false; + JSValue leftConst = forNode(node.child1()).value(); JSValue rightConst = forNode(node.child2()).value(); if (leftConst && rightConst && leftConst.isNumber() && rightConst.isNumber()) { double a = leftConst.asNumber(); double b = rightConst.asNumber(); - bool constantWasSet; switch (node.op()) { case CompareLess: constantWasSet = trySetConstant(nodeIndex, jsBoolean(a < b)); @@ -705,11 +724,20 @@ bool AbstractState::execute(unsigned indexInBlock) constantWasSet = false; break; } - if (constantWasSet) { - m_foundConstants = true; - node.setCanExit(false); - break; - } + } + + if (!constantWasSet && node.op() == CompareEq) { + SpeculatedType leftType = forNode(node.child1()).m_type; + SpeculatedType rightType = forNode(node.child2()).m_type; + if ((isInt32Speculation(leftType) && isOtherSpeculation(rightType)) + || (isOtherSpeculation(leftType) && isInt32Speculation(rightType))) + constantWasSet = trySetConstant(nodeIndex, jsBoolean(false)); + } + + if (constantWasSet) { + m_foundConstants = true; + node.setCanExit(false); + break; } forNode(nodeIndex).set(SpecBoolean); @@ -842,6 +870,7 @@ bool AbstractState::execute(unsigned indexInBlock) switch (node.arrayMode().type()) { case Array::SelectUsingPredictions: case Array::Unprofiled: + case Array::Undecided: ASSERT_NOT_REACHED(); break; case Array::ForceExit: @@ -859,6 +888,22 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).makeTop(); break; + case Array::Int32: + forNode(node.child2()).filter(SpecInt32); + if (node.arrayMode().isOutOfBounds()) { + clobberWorld(node.codeOrigin, indexInBlock); + forNode(nodeIndex).makeTop(); + } else + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Double: + forNode(node.child2()).filter(SpecInt32); + if (node.arrayMode().isOutOfBounds()) { + clobberWorld(node.codeOrigin, indexInBlock); + forNode(nodeIndex).makeTop(); + } else + forNode(nodeIndex).set(SpecDoubleReal); + break; case Array::Contiguous: case Array::ArrayStorage: case Array::SlowPutArrayStorage: @@ -926,6 +971,20 @@ bool AbstractState::execute(unsigned indexInBlock) case Array::Generic: clobberWorld(node.codeOrigin, indexInBlock); break; + case Array::Int32: + forNode(child1).filter(SpecCell); + forNode(child2).filter(SpecInt32); + forNode(child3).filter(SpecInt32); + if (node.arrayMode().isOutOfBounds()) + clobberWorld(node.codeOrigin, indexInBlock); + break; + case Array::Double: + forNode(child1).filter(SpecCell); + forNode(child2).filter(SpecInt32); + forNode(child3).filter(SpecRealNumber); + if (node.arrayMode().isOutOfBounds()) + clobberWorld(node.codeOrigin, indexInBlock); + break; case Array::Contiguous: case Array::ArrayStorage: forNode(child1).filter(SpecCell); @@ -1018,6 +1077,16 @@ bool AbstractState::execute(unsigned indexInBlock) case ArrayPush: node.setCanExit(true); + switch (node.arrayMode().type()) { + case Array::Int32: + forNode(node.child2()).filter(SpecInt32); + break; + case Array::Double: + forNode(node.child2()).filter(SpecRealNumber); + break; + default: + break; + } clobberWorld(node.codeOrigin, indexInBlock); forNode(nodeIndex).set(SpecNumber); break; @@ -1043,6 +1112,7 @@ bool AbstractState::execute(unsigned indexInBlock) break; case Branch: { + // First check if we can fold because the source is a constant. JSValue value = forNode(node.child1()).value(); if (value) { bool booleanValue = value.toBoolean(m_codeBlock->globalObjectFor(node.codeOrigin)->globalExec()); @@ -1053,6 +1123,14 @@ bool AbstractState::execute(unsigned indexInBlock) node.setCanExit(false); break; } + // Next check if we can fold because we know that the source is an object or string and does not equal undefined. + if (isCellSpeculation(forNode(node.child1()).m_type) + && forNode(node.child1()).m_currentKnownStructure.hasSingleton() + && !forNode(node.child1()).m_currentKnownStructure.singleton()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node.codeOrigin))) { + m_branchDirection = TakeTrue; + node.setCanExit(false); + break; + } // FIXME: The above handles the trivial cases of sparse conditional // constant propagation, but we can do better: // 1) If the abstract value does not have a concrete value but describes @@ -1122,13 +1200,13 @@ bool AbstractState::execute(unsigned indexInBlock) case NewArray: node.setCanExit(true); - forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure()); + forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())); m_haveStructures = true; break; case NewArrayBuffer: node.setCanExit(true); - forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure()); + forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())); m_haveStructures = true; break; @@ -1384,11 +1462,11 @@ bool AbstractState::execute(unsigned indexInBlock) case Array::String: forNode(node.child1()).filter(SpecString); break; + case Array::Int32: + case Array::Double: case Array::Contiguous: case Array::ArrayStorage: case Array::SlowPutArrayStorage: - // This doesn't filter anything meaningful right now. We may want to add - // CFA tracking of array mode speculations, but we don't have that, yet. forNode(node.child1()).filter(SpecCell); break; case Array::Arguments: @@ -1722,7 +1800,7 @@ inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to) } inline bool AbstractState::mergeToSuccessors( - Graph& graph, BasicBlock* basicBlock, BranchDirection branchDirection) + Graph& graph, BasicBlock* basicBlock) { Node& terminal = graph[basicBlock->last()]; @@ -1730,7 +1808,7 @@ inline bool AbstractState::mergeToSuccessors( switch (terminal.op()) { case Jump: { - ASSERT(branchDirection == InvalidBranchDirection); + ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog(" Merging to block #%u.\n", terminal.takenBlockIndex()); #endif @@ -1738,17 +1816,17 @@ inline bool AbstractState::mergeToSuccessors( } case Branch: { - ASSERT(branchDirection != InvalidBranchDirection); + ASSERT(basicBlock->cfaBranchDirection != InvalidBranchDirection); bool changed = false; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog(" Merging to block #%u.\n", terminal.takenBlockIndex()); #endif - if (branchDirection != TakeFalse) + if (basicBlock->cfaBranchDirection != TakeFalse) changed |= merge(basicBlock, graph.m_blocks[terminal.takenBlockIndex()].get()); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog(" Merging to block #%u.\n", terminal.notTakenBlockIndex()); #endif - if (branchDirection != TakeTrue) + if (basicBlock->cfaBranchDirection != TakeTrue) changed |= merge(basicBlock, graph.m_blocks[terminal.notTakenBlockIndex()].get()); return changed; } @@ -1756,7 +1834,7 @@ inline bool AbstractState::mergeToSuccessors( case Return: case Throw: case ThrowReferenceError: - ASSERT(branchDirection == InvalidBranchDirection); + ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection); return false; default: diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h index ec1a06231..0e33140c0 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.h +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.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 @@ -31,6 +31,7 @@ #if ENABLE(DFG_JIT) #include "DFGAbstractValue.h" +#include "DFGBranchDirection.h" #include "DFGGraph.h" #include "DFGNode.h" #include <wtf/Vector.h> @@ -92,36 +93,6 @@ public: MergeToSuccessors }; - enum BranchDirection { - // This is not a branch and so there is no branch direction, or - // the branch direction has yet to be set. - InvalidBranchDirection, - - // The branch takes the true case. - TakeTrue, - - // The branch takes the false case. - TakeFalse, - - // For all we know, the branch could go either direction, so we - // have to assume the worst. - TakeBoth - }; - - static const char* branchDirectionToString(BranchDirection branchDirection) - { - switch (branchDirection) { - case InvalidBranchDirection: - return "Invalid"; - case TakeTrue: - return "TakeTrue"; - case TakeFalse: - return "TakeFalse"; - case TakeBoth: - return "TakeBoth"; - } - } - AbstractState(Graph&); ~AbstractState(); @@ -174,11 +145,7 @@ public: // A true return means that you must revisit (at least) the successor // blocks. This also sets cfaShouldRevisit to true for basic blocks // that must be visited next. - // - // If you'd like to know what direction the branch at the end of the - // basic block is thought to have taken, you can pass a non-0 pointer - // for BranchDirection. - bool endBasicBlock(MergeMode, BranchDirection* = 0); + bool endBasicBlock(MergeMode); // Reset the AbstractState. This throws away any results, and at this point // you can safely call beginBasicBlock() on any basic block. @@ -211,8 +178,8 @@ public: // successors. Returns true if any of the successors' states changed. Note // that this is automatically called in endBasicBlock() if MergeMode is // MergeToSuccessors. - bool mergeToSuccessors(Graph&, BasicBlock*, BranchDirection); - + bool mergeToSuccessors(Graph&, BasicBlock*); + void dump(FILE* out); private: diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp index 699902a16..0d15b9a30 100644 --- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp +++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp @@ -34,19 +34,46 @@ namespace JSC { namespace DFG { ArrayMode ArrayMode::fromObserved(ArrayProfile* profile, Array::Action action, bool makeSafe) { - switch (profile->observedArrayModes()) { + ArrayModes observed = profile->observedArrayModes(); + switch (observed) { case 0: return ArrayMode(Array::Unprofiled); case asArrayModes(NonArray): if (action == Array::Write && !profile->mayInterceptIndexedAccesses()) - return ArrayMode(Array::Contiguous, Array::NonArray, Array::OutOfBounds, Array::Convert); // FIXME: we don't know whether to go to contiguous or array storage. We're making a static guess here. In future we should use exit profiling for this. + return ArrayMode(Array::Undecided, Array::NonArray, Array::OutOfBounds, Array::Convert); return ArrayMode(Array::SelectUsingPredictions); + + case asArrayModes(ArrayWithUndecided): + if (action == Array::Write) + return ArrayMode(Array::Undecided, Array::Array, Array::OutOfBounds, Array::Convert); + return ArrayMode(Array::Generic); + + case asArrayModes(NonArray) | asArrayModes(ArrayWithUndecided): + if (action == Array::Write && !profile->mayInterceptIndexedAccesses()) + return ArrayMode(Array::Undecided, Array::PossiblyArray, Array::OutOfBounds, Array::Convert); + return ArrayMode(Array::SelectUsingPredictions); + + case asArrayModes(NonArrayWithInt32): + return ArrayMode(Array::Int32, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe); + case asArrayModes(ArrayWithInt32): + return ArrayMode(Array::Int32, Array::Array, Array::AsIs).withProfile(profile, makeSafe); + case asArrayModes(NonArrayWithInt32) | asArrayModes(ArrayWithInt32): + return ArrayMode(Array::Int32, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe); + + case asArrayModes(NonArrayWithDouble): + return ArrayMode(Array::Double, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe); + case asArrayModes(ArrayWithDouble): + return ArrayMode(Array::Double, Array::Array, Array::AsIs).withProfile(profile, makeSafe); + case asArrayModes(NonArrayWithDouble) | asArrayModes(ArrayWithDouble): + return ArrayMode(Array::Double, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe); + case asArrayModes(NonArrayWithContiguous): return ArrayMode(Array::Contiguous, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe); case asArrayModes(ArrayWithContiguous): return ArrayMode(Array::Contiguous, Array::Array, Array::AsIs).withProfile(profile, makeSafe); case asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous): return ArrayMode(Array::Contiguous, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe); + case asArrayModes(NonArrayWithArrayStorage): return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe); case asArrayModes(NonArrayWithSlowPutArrayStorage): @@ -62,36 +89,39 @@ ArrayMode ArrayMode::fromObserved(ArrayProfile* profile, Array::Action action, b case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe); - case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage): - return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::Convert).withProfile(profile, makeSafe); - case asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage): - return ArrayMode(Array::ArrayStorage, Array::Array, Array::Convert).withProfile(profile, makeSafe); - case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage): - return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::Convert).withProfile(profile, makeSafe); - case asArrayModes(NonArray) | asArrayModes(NonArrayWithContiguous): - if (action == Array::Write && !profile->mayInterceptIndexedAccesses()) - return ArrayMode(Array::Contiguous, Array::NonArray, Array::OutOfBounds, Array::Convert); - return ArrayMode(Array::SelectUsingPredictions); - case asArrayModes(NonArray) | asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage): - case asArrayModes(NonArray) | asArrayModes(NonArrayWithArrayStorage): - if (action == Array::Write && !profile->mayInterceptIndexedAccesses()) - return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::OutOfBounds, Array::Convert); - return ArrayMode(Array::SelectUsingPredictions); - case asArrayModes(NonArray) | asArrayModes(NonArrayWithSlowPutArrayStorage): - case asArrayModes(NonArray) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage): - if (action == Array::Write && !profile->mayInterceptIndexedAccesses()) - return ArrayMode(Array::SlowPutArrayStorage, Array::NonArray, Array::OutOfBounds, Array::Convert); - return ArrayMode(Array::SelectUsingPredictions); + default: - // We know that this is possibly a kind of array for which, though there is no - // useful data in the array profile, we may be able to extract useful data from - // the value profiles of the inputs. Hence, we leave it as undecided, and let - // the predictions propagator decide later. - return ArrayMode(Array::SelectUsingPredictions); + if ((observed & asArrayModes(NonArray)) && profile->mayInterceptIndexedAccesses()) + return ArrayMode(Array::SelectUsingPredictions); + + Array::Type type; + Array::Class arrayClass; + + if (shouldUseSlowPutArrayStorage(observed)) + type = Array::SlowPutArrayStorage; + else if (shouldUseFastArrayStorage(observed)) + type = Array::ArrayStorage; + else if (shouldUseContiguous(observed)) + type = Array::Contiguous; + else if (shouldUseDouble(observed)) + type = Array::Double; + else if (shouldUseInt32(observed)) + type = Array::Int32; + else + type = Array::Undecided; + + if (observed & (asArrayModes(ArrayWithUndecided) | asArrayModes(ArrayWithInt32) | asArrayModes(ArrayWithDouble) | asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage))) + arrayClass = Array::Array; + else if (observed & (asArrayModes(NonArray) | asArrayModes(NonArrayWithInt32) | asArrayModes(NonArrayWithDouble) | asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage))) + arrayClass = Array::NonArray; + else + arrayClass = Array::PossiblyArray; + + return ArrayMode(type, arrayClass, Array::Convert).withProfile(profile, makeSafe); } } -ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index) const +ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, SpeculatedType value) const { if (!base || !index) { // It can be that we had a legitimate arrayMode but no incoming predictions. That'll @@ -104,49 +134,85 @@ ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index) const if (!isInt32Speculation(index) || !isCellSpeculation(base)) return ArrayMode(Array::Generic); - if (type() == Array::Unprofiled) { - // If the indexing type wasn't recorded in the array profile but the values are - // base=cell property=int, then we know that this access didn't execute. + switch (type()) { + case Array::Unprofiled: return ArrayMode(Array::ForceExit); - } - - if (type() != Array::SelectUsingPredictions) + + case Array::Undecided: + if (!value) + return withType(Array::ForceExit); + if (isInt32Speculation(value)) + return withTypeAndConversion(Array::Int32, Array::Convert); + if (isNumberSpeculation(value)) + return withTypeAndConversion(Array::Double, Array::Convert); + return withTypeAndConversion(Array::Contiguous, Array::Convert); + + case Array::Int32: + if (!value || isInt32Speculation(value)) + return *this; + if (isNumberSpeculation(value)) + return withTypeAndConversion(Array::Double, Array::Convert); + return withTypeAndConversion(Array::Contiguous, Array::Convert); + + case Array::Double: + if (!value || isNumberSpeculation(value)) + return *this; + return withTypeAndConversion(Array::Contiguous, Array::Convert); + + case Array::SelectUsingPredictions: + if (isStringSpeculation(base)) + return ArrayMode(Array::String); + + if (isArgumentsSpeculation(base)) + return ArrayMode(Array::Arguments); + + if (isInt8ArraySpeculation(base)) + return ArrayMode(Array::Int8Array); + + if (isInt16ArraySpeculation(base)) + return ArrayMode(Array::Int16Array); + + if (isInt32ArraySpeculation(base)) + return ArrayMode(Array::Int32Array); + + if (isUint8ArraySpeculation(base)) + return ArrayMode(Array::Uint8Array); + + if (isUint8ClampedArraySpeculation(base)) + return ArrayMode(Array::Uint8ClampedArray); + + if (isUint16ArraySpeculation(base)) + return ArrayMode(Array::Uint16Array); + + if (isUint32ArraySpeculation(base)) + return ArrayMode(Array::Uint32Array); + + if (isFloat32ArraySpeculation(base)) + return ArrayMode(Array::Float32Array); + + if (isFloat64ArraySpeculation(base)) + return ArrayMode(Array::Float64Array); + + return ArrayMode(Array::Generic); + + default: return *this; - - if (isStringSpeculation(base)) - return ArrayMode(Array::String); - - if (isArgumentsSpeculation(base)) - return ArrayMode(Array::Arguments); - - if (isInt8ArraySpeculation(base)) - return ArrayMode(Array::Int8Array); - - if (isInt16ArraySpeculation(base)) - return ArrayMode(Array::Int16Array); - - if (isInt32ArraySpeculation(base)) - return ArrayMode(Array::Int32Array); - - if (isUint8ArraySpeculation(base)) - return ArrayMode(Array::Uint8Array); - - if (isUint8ClampedArraySpeculation(base)) - return ArrayMode(Array::Uint8ClampedArray); - - if (isUint16ArraySpeculation(base)) - return ArrayMode(Array::Uint16Array); - - if (isUint32ArraySpeculation(base)) - return ArrayMode(Array::Uint32Array); - - if (isFloat32ArraySpeculation(base)) - return ArrayMode(Array::Float32Array); - - if (isFloat64ArraySpeculation(base)) - return ArrayMode(Array::Float64Array); - - return ArrayMode(Array::Generic); + } +} + +bool ArrayMode::alreadyChecked(AbstractValue& value, IndexingType shape) const +{ + if (isJSArray()) { + if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape | IsArray))) + return true; + return value.m_currentKnownStructure.hasSingleton() + && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape + && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray); + } + if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape) | asArrayModes(shape | IsArray))) + return true; + return value.m_currentKnownStructure.hasSingleton() + && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape; } bool ArrayMode::alreadyChecked(AbstractValue& value) const @@ -161,31 +227,17 @@ bool ArrayMode::alreadyChecked(AbstractValue& value) const case Array::String: return speculationChecked(value.m_type, SpecString); + case Array::Int32: + return alreadyChecked(value, Int32Shape); + + case Array::Double: + return alreadyChecked(value, DoubleShape); + case Array::Contiguous: - if (isJSArray()) { - if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithContiguous))) - return true; - return value.m_currentKnownStructure.hasSingleton() - && hasContiguous(value.m_currentKnownStructure.singleton()->indexingType()) - && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray); - } - if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous))) - return true; - return value.m_currentKnownStructure.hasSingleton() - && hasContiguous(value.m_currentKnownStructure.singleton()->indexingType()); + return alreadyChecked(value, ContiguousShape); case Array::ArrayStorage: - if (isJSArray()) { - if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage))) - return true; - return value.m_currentKnownStructure.hasSingleton() - && hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType()) - && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray); - } - if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage))) - return true; - return value.m_currentKnownStructure.hasSingleton() - && hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType()); + return alreadyChecked(value, ArrayStorageShape); case Array::SlowPutArrayStorage: if (isJSArray()) { @@ -232,6 +284,7 @@ bool ArrayMode::alreadyChecked(AbstractValue& value) const case Array::SelectUsingPredictions: case Array::Unprofiled: + case Array::Undecided: break; } @@ -252,6 +305,12 @@ const char* arrayTypeToString(Array::Type type) return "ForceExit"; case Array::String: return "String"; + case Array::Undecided: + return "Undecided"; + case Array::Int32: + return "Int32"; + case Array::Double: + return "Double"; case Array::Contiguous: return "Contiguous"; case Array::ArrayStorage: diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h index 615965c92..206d689f2 100644 --- a/Source/JavaScriptCore/dfg/DFGArrayMode.h +++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h @@ -52,7 +52,10 @@ enum Type { ForceExit, // Implies that we have no idea how to execute this operation, so we should just give up. Generic, String, - + + Undecided, + Int32, + Double, Contiguous, ArrayStorage, SlowPutArrayStorage, @@ -81,7 +84,6 @@ enum Speculation { ToHole, OutOfBounds }; - enum Conversion { AsIs, Convert @@ -169,7 +171,17 @@ public: return ArrayMode(type(), myArrayClass, mySpeculation, conversion()); } - ArrayMode refine(SpeculatedType base, SpeculatedType index) const; + ArrayMode withType(Array::Type type) const + { + return ArrayMode(type, arrayClass(), speculation(), conversion()); + } + + ArrayMode withTypeAndConversion(Array::Type type, Array::Conversion conversion) const + { + return ArrayMode(type, arrayClass(), speculation(), conversion); + } + + ArrayMode refine(SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone) const; bool alreadyChecked(AbstractValue&) const; @@ -178,6 +190,8 @@ public: bool usesButterfly() const { switch (type()) { + case Array::Int32: + case Array::Double: case Array::Contiguous: case Array::ArrayStorage: case Array::SlowPutArrayStorage: @@ -263,6 +277,7 @@ public: case Array::Unprofiled: case Array::ForceExit: case Array::Generic: + case Array::Undecided: return false; default: return true; @@ -277,6 +292,8 @@ public: case Array::ForceExit: case Array::Generic: return false; + case Array::Int32: + case Array::Double: case Array::Contiguous: case Array::ArrayStorage: case Array::SlowPutArrayStorage: @@ -309,6 +326,10 @@ public: switch (type()) { case Array::Generic: return ALL_ARRAY_MODES; + case Array::Int32: + return arrayModesWithIndexingShape(Int32Shape); + case Array::Double: + return arrayModesWithIndexingShape(DoubleShape); case Array::Contiguous: return arrayModesWithIndexingShape(ContiguousShape); case Array::ArrayStorage: @@ -354,6 +375,8 @@ private: } } + bool alreadyChecked(AbstractValue&, IndexingType shape) const; + union { struct { uint8_t type; diff --git a/Source/JavaScriptCore/dfg/DFGBasicBlock.h b/Source/JavaScriptCore/dfg/DFGBasicBlock.h index 441e2e75e..6f348f2e1 100644 --- a/Source/JavaScriptCore/dfg/DFGBasicBlock.h +++ b/Source/JavaScriptCore/dfg/DFGBasicBlock.h @@ -29,6 +29,7 @@ #if ENABLE(DFG_JIT) #include "DFGAbstractValue.h" +#include "DFGBranchDirection.h" #include "DFGNode.h" #include "Operands.h" #include <wtf/OwnPtr.h> @@ -46,6 +47,7 @@ struct BasicBlock : Vector<NodeIndex, 8> { , cfaShouldRevisit(false) , cfaFoundConstants(false) , cfaDidFinish(true) + , cfaBranchDirection(InvalidBranchDirection) #if !ASSERT_DISABLED , isLinked(false) #endif @@ -105,6 +107,7 @@ struct BasicBlock : Vector<NodeIndex, 8> { bool cfaShouldRevisit; bool cfaFoundConstants; bool cfaDidFinish; + BranchDirection cfaBranchDirection; #if !ASSERT_DISABLED bool isLinked; #endif diff --git a/Source/JavaScriptCore/dfg/DFGBranchDirection.h b/Source/JavaScriptCore/dfg/DFGBranchDirection.h new file mode 100644 index 000000000..8bbe3c635 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGBranchDirection.h @@ -0,0 +1,88 @@ +/* + * 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 DFGBranchDirection_h +#define DFGBranchDirection_h + +#include <wtf/Platform.h> + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +enum BranchDirection { + // This is not a branch and so there is no branch direction, or + // the branch direction has yet to be set. + InvalidBranchDirection, + + // The branch takes the true case. + TakeTrue, + + // The branch takes the false case. + TakeFalse, + + // For all we know, the branch could go either direction, so we + // have to assume the worst. + TakeBoth +}; + +static inline const char* branchDirectionToString(BranchDirection branchDirection) +{ + switch (branchDirection) { + case InvalidBranchDirection: + return "Invalid"; + case TakeTrue: + return "TakeTrue"; + case TakeFalse: + return "TakeFalse"; + case TakeBoth: + return "TakeBoth"; + } +} + +static inline bool isKnownDirection(BranchDirection branchDirection) +{ + switch (branchDirection) { + case TakeTrue: + case TakeFalse: + return true; + default: + return false; + } +} + +static inline bool branchCondition(BranchDirection branchDirection) +{ + if (branchDirection == TakeTrue) + return true; + ASSERT(branchDirection == TakeFalse); + return false; +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGBranchDirection_h diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 70aa2b637..142b8ab95 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -905,10 +905,15 @@ private: return getPrediction(m_graph.size(), m_currentProfilingIndex); } - ArrayMode getArrayMode(ArrayProfile* profile) + ArrayMode getArrayMode(ArrayProfile* profile, Array::Action action) { profile->computeUpdatedPrediction(m_inlineStackTop->m_codeBlock); - return ArrayMode::fromObserved(profile, Array::Read, false); + return ArrayMode::fromObserved(profile, action, false); + } + + ArrayMode getArrayMode(ArrayProfile* profile) + { + return getArrayMode(profile, Array::Read); } ArrayMode getArrayModeAndEmitChecks(ArrayProfile* profile, Array::Action action, NodeIndex base) @@ -1649,7 +1654,12 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; ArrayMode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile); + if (!arrayMode.isJSArray()) + return false; switch (arrayMode.type()) { + case Array::Undecided: + case Array::Int32: + case Array::Double: case Array::Contiguous: case Array::ArrayStorage: { NodeIndex arrayPush = addToGraph(ArrayPush, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(registerOffset + argumentToOperand(0)), get(registerOffset + argumentToOperand(1))); @@ -1669,7 +1679,11 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; ArrayMode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile); + if (!arrayMode.isJSArray()) + return false; switch (arrayMode.type()) { + case Array::Int32: + case Array::Double: case Array::Contiguous: case Array::ArrayStorage: { NodeIndex arrayPop = addToGraph(ArrayPop, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(registerOffset + argumentToOperand(0))); @@ -1754,7 +1768,7 @@ bool ByteCodeParser::handleConstantInternalFunction( if (argumentCountIncludingThis == 2) { setIntrinsicResult( usesResult, resultOperand, - addToGraph(NewArrayWithSize, get(registerOffset + argumentToOperand(1)))); + addToGraph(NewArrayWithSize, OpInfo(ArrayWithUndecided), get(registerOffset + argumentToOperand(1)))); return true; } @@ -1762,7 +1776,7 @@ bool ByteCodeParser::handleConstantInternalFunction( addVarArgChild(get(registerOffset + argumentToOperand(i))); setIntrinsicResult( usesResult, resultOperand, - addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0))); + addToGraph(Node::VarArg, NewArray, OpInfo(ArrayWithUndecided), OpInfo(0))); return true; } @@ -2122,24 +2136,37 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_new_array: { int startOperand = currentInstruction[2].u.operand; int numOperands = currentInstruction[3].u.operand; + ArrayAllocationProfile* profile = currentInstruction[4].u.arrayAllocationProfile; for (int operandIdx = startOperand; operandIdx < startOperand + numOperands; ++operandIdx) addVarArgChild(get(operandIdx)); - set(currentInstruction[1].u.operand, addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0))); + set(currentInstruction[1].u.operand, addToGraph(Node::VarArg, NewArray, OpInfo(profile->selectIndexingType()), OpInfo(0))); NEXT_OPCODE(op_new_array); } case op_new_array_with_size: { int lengthOperand = currentInstruction[2].u.operand; - set(currentInstruction[1].u.operand, addToGraph(NewArrayWithSize, get(lengthOperand))); + ArrayAllocationProfile* profile = currentInstruction[3].u.arrayAllocationProfile; + set(currentInstruction[1].u.operand, addToGraph(NewArrayWithSize, OpInfo(profile->selectIndexingType()), get(lengthOperand))); NEXT_OPCODE(op_new_array_with_size); } case op_new_array_buffer: { int startConstant = currentInstruction[2].u.operand; int numConstants = currentInstruction[3].u.operand; + ArrayAllocationProfile* profile = currentInstruction[4].u.arrayAllocationProfile; NewArrayBufferData data; data.startConstant = m_inlineStackTop->m_constantBufferRemap[startConstant]; data.numConstants = numConstants; + data.indexingType = profile->selectIndexingType(); + + // If this statement has never executed, we'll have the wrong indexing type in the profile. + for (int i = 0; i < numConstants; ++i) { + data.indexingType = + leastUpperBoundOfIndexingTypeAndValue( + data.indexingType, + m_codeBlock->constantBuffer(data.startConstant)[i]); + } + m_graph.m_newArrayBufferData.append(data); set(currentInstruction[1].u.operand, addToGraph(NewArrayBuffer, OpInfo(&m_graph.m_newArrayBufferData.last()))); NEXT_OPCODE(op_new_array_buffer); diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h index a2570b7ea..308dde5a6 100644 --- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h @@ -210,6 +210,15 @@ public: addCallArgument(arg3); } + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, GPRReg arg3) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + } + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, TrustedImmPtr arg3) { resetCallArguments(); @@ -268,6 +277,16 @@ public: addCallArgument(arg4); } + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + addCallArgument(arg4); + } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImmPtr arg2, GPRReg arg3) { resetCallArguments(); @@ -317,6 +336,23 @@ public: addCallArgument(arg4); addCallArgument(arg5); } + + ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + } #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. @@ -463,6 +499,20 @@ public: { setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2); } + + ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2) + { + moveDouble(arg1, FPRInfo::argumentFPR0); + move(arg2, GPRInfo::argumentGPR1); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3) + { + moveDouble(arg3, FPRInfo::argumentFPR0); + setupStubArguments(arg1, arg2); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } #elif CPU(ARM) #if CPU(ARM_HARDFP) ALWAYS_INLINE void setupArguments(FPRReg arg1) @@ -496,6 +546,21 @@ public: assembler().vmov(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, arg1); assembler().vmov(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, arg2); } + + ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2) + { + move(arg2, GPRInfo::argumentGPR3); + assembler().vmov(GPRInfo::argumentGPR1, GPRInfo::argumentGPR2, arg1); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3) + { + setupStubArguments(arg1, arg2); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + assembler().vmov(GPRInfo::argumentGPR3, GPRInfo::nonArgGPR0, arg3); + poke(GPRInfo::nonArgGPR0); + } #endif // CPU(ARM_HARDFP) #else #error "DFG JIT not supported on this platform." @@ -635,6 +700,13 @@ public: move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); } + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, GPRReg arg3) + { + setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3>(arg1, arg3); + move(arg2, GPRInfo::argumentGPR2); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, TrustedImmPtr arg3) { move(arg1, GPRInfo::argumentGPR1); @@ -723,6 +795,12 @@ public: setupArgumentsWithExecState(arg1, arg2, arg3); } + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4) + { + poke(arg4); + setupArgumentsWithExecState(arg1, arg2, arg3); + } + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImm32 arg3, GPRReg arg4) { poke(arg4); diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp index e0d973992..e3827d8ad 100644 --- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp @@ -99,9 +99,8 @@ public: case Branch: { // Branch on constant -> jettison the not-taken block and merge. - if (m_graph[m_graph[block->last()].child1()].hasConstant()) { - bool condition = - m_graph.valueOfJSConstant(m_graph[block->last()].child1().index()).toBoolean(m_graph.globalObjectFor(m_graph[block->last()].codeOrigin)->globalExec()); + if (isKnownDirection(block->cfaBranchDirection)) { + bool condition = branchCondition(block->cfaBranchDirection); BasicBlock* targetBlock = m_graph.m_blocks[ m_graph.successorForCondition(block, condition)].get(); if (targetBlock->m_predecessors.size() == 1) { @@ -730,6 +729,7 @@ private: } firstBlock->valuesAtTail = secondBlock->valuesAtTail; + firstBlock->cfaBranchDirection = secondBlock->cfaBranchDirection; m_graph.m_blocks[secondBlockIndex].clear(); } diff --git a/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h b/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h index 46d5f44cb..03713b6c5 100644 --- a/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h +++ b/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h @@ -61,7 +61,7 @@ protected: jit->silentSpill(m_plans[i]); jit->callOperation(m_function, m_resultGPR, m_structure, m_size); GPRReg canTrample = SpeculativeJIT::pickCanTrample(m_resultGPR); - for (unsigned i = 0; i < m_plans.size(); ++i) + for (unsigned i = m_plans.size(); i--;) jit->silentFill(m_plans[i], canTrample); jit->m_jit.loadPtr(MacroAssembler::Address(m_resultGPR, JSObject::butterflyOffset()), m_storageGPR); jumpTo(jit); @@ -106,7 +106,7 @@ protected: done.link(&jit->m_jit); jit->callOperation(m_function, m_resultGPR, scratchGPR, m_sizeGPR); GPRReg canTrample = SpeculativeJIT::pickCanTrample(m_resultGPR); - for (unsigned i = 0; i < m_plans.size(); ++i) + for (unsigned i = m_plans.size(); i--;) jit->silentFill(m_plans[i], canTrample); jumpTo(jit); } diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp index 5a76aa8df..621d6e96a 100644 --- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp @@ -145,7 +145,30 @@ private: } case ArrayPush: { + // May need to refine the array mode in case the value prediction contravenes + // the array prediction. For example, we may have evidence showing that the + // array is in Int32 mode, but the value we're storing is likely to be a double. + // Then we should turn this into a conversion to Double array followed by the + // push. On the other hand, we absolutely don't want to refine based on the + // base prediction. If it has non-cell garbage in it, then we want that to be + // ignored. That's because ArrayPush can't handle any array modes that aren't + // array-related - so if refine() turned this into a "Generic" ArrayPush then + // that would break things. + node.setArrayMode( + node.arrayMode().refine( + m_graph[node.child1()].prediction() & SpecCell, + SpecInt32, + m_graph[node.child2()].prediction())); blessArrayOperation(node.child1(), node.child2(), 2); + + Node* nodePtr = &m_graph[m_compileIndex]; + switch (nodePtr->arrayMode().type()) { + case Array::Double: + fixDoubleEdge(1); + break; + default: + break; + } break; } @@ -236,7 +259,7 @@ private: case ValueAdd: { if (m_graph.addShouldSpeculateInteger(node)) break; - if (!Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()])) + if (!Node::shouldSpeculateNumberExpectingDefined(m_graph[node.child1()], m_graph[node.child2()])) break; fixDoubleEdge(0); fixDoubleEdge(1); @@ -262,7 +285,7 @@ private: case ArithMin: case ArithMax: case ArithMod: { - if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]) + if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) break; fixDoubleEdge(0); @@ -279,7 +302,7 @@ private: } case ArithDiv: { - if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]) + if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) { if (isX86()) break; @@ -307,7 +330,7 @@ private: } case ArithAbs: { - if (m_graph[node.child1()].shouldSpeculateInteger() + if (m_graph[node.child1()].shouldSpeculateIntegerForArithmetic() && node.canSpeculateInteger()) break; fixDoubleEdge(0); @@ -328,13 +351,17 @@ private: node.setArrayMode( node.arrayMode().refine( m_graph[child1].prediction(), - m_graph[child2].prediction())); + m_graph[child2].prediction(), + m_graph[child3].prediction())); blessArrayOperation(child1, child2, 3); Node* nodePtr = &m_graph[m_compileIndex]; switch (nodePtr->arrayMode().modeForPut().type()) { + case Array::Double: + fixDoubleEdge(2); + break; case Array::Int8Array: case Array::Int16Array: case Array::Int32Array: @@ -355,6 +382,19 @@ private: break; } + case NewArray: { + for (unsigned i = m_graph.varArgNumChildren(node); i--;) { + node.setIndexingType( + leastUpperBoundOfIndexingTypeAndType( + node.indexingType(), m_graph[m_graph.varArgChild(node, i)].prediction())); + } + if (node.indexingType() == ArrayWithDouble) { + for (unsigned i = m_graph.varArgNumChildren(node); i--;) + fixDoubleEdge(i); + } + break; + } + default: break; } @@ -392,15 +432,17 @@ private: if (arrayMode.isJSArrayWithOriginalStructure()) { JSGlobalObject* globalObject = m_graph.baselineCodeBlockFor(codeOrigin)->globalObject(); switch (arrayMode.type()) { + case Array::Int32: + structure = globalObject->originalArrayStructureForIndexingType(ArrayWithInt32); + break; + case Array::Double: + structure = globalObject->originalArrayStructureForIndexingType(ArrayWithDouble); + break; case Array::Contiguous: - structure = globalObject->arrayStructure(); - if (structure->indexingType() != ArrayWithContiguous) - structure = 0; + structure = globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous); break; case Array::ArrayStorage: - structure = globalObject->arrayStructureWithArrayStorage(); - if (structure->indexingType() != ArrayWithArrayStorage) - structure = 0; + structure = globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage); break; default: break; diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp index 8e8817f81..38079f020 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.cpp +++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp @@ -287,6 +287,11 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex) dataLog("]"); hasPrinted = true; } + if (node.hasIndexingType()) { + if (hasPrinted) + dataLog(", "); + dataLog("%s", indexingTypeToString(node.indexingType())); + } if (op == JSConstant) { dataLog("%s$%u", hasPrinted ? ", " : "", node.constantNumber()); JSValue value = valueOfJSConstant(nodeIndex); diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index 9fbb2df07..4de2e0e26 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -220,7 +220,7 @@ public: if (right.hasConstant()) return addImmediateShouldSpeculateInteger(add, left, right); - return Node::shouldSpeculateInteger(left, right) && add.canSpeculateInteger(); + return Node::shouldSpeculateIntegerExpectingDefined(left, right) && add.canSpeculateInteger(); } bool mulShouldSpeculateInteger(Node& mul) @@ -235,13 +235,13 @@ public: if (right.hasConstant()) return mulImmediateShouldSpeculateInteger(mul, left, right); - return Node::shouldSpeculateInteger(left, right) && mul.canSpeculateInteger() && !nodeMayOverflow(mul.arithNodeFlags()); + return Node::shouldSpeculateIntegerForArithmetic(left, right) && mul.canSpeculateInteger() && !nodeMayOverflow(mul.arithNodeFlags()); } bool negateShouldSpeculateInteger(Node& negate) { ASSERT(negate.op() == ArithNegate); - return at(negate.child1()).shouldSpeculateInteger() && negate.canSpeculateInteger(); + return at(negate.child1()).shouldSpeculateIntegerForArithmetic() && negate.canSpeculateInteger(); } bool addShouldSpeculateInteger(NodeIndex nodeIndex) @@ -493,6 +493,8 @@ public: switch (node.arrayMode().type()) { case Array::Generic: return false; + case Array::Int32: + case Array::Double: case Array::Contiguous: case Array::ArrayStorage: return !node.arrayMode().isOutOfBounds(); @@ -712,7 +714,7 @@ private: if (!immediateValue.isNumber()) return false; - if (!variable.shouldSpeculateInteger()) + if (!variable.shouldSpeculateIntegerExpectingDefined()) return false; if (immediateValue.isInt32()) @@ -734,7 +736,7 @@ private: if (!immediateValue.isInt32()) return false; - if (!variable.shouldSpeculateInteger()) + if (!variable.shouldSpeculateIntegerForArithmetic()) return false; int32_t intImmediate = immediateValue.asInt32(); diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index e66629ec4..bff7fe65f 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -62,6 +62,7 @@ struct StructureTransitionData { struct NewArrayBufferData { unsigned startConstant; unsigned numConstants; + IndexingType indexingType; }; // This type used in passing an immediate argument to Node constructor; @@ -433,6 +434,32 @@ struct Node { return newArrayBufferData()->numConstants; } + bool hasIndexingType() + { + switch (op()) { + case NewArray: + case NewArrayWithSize: + case NewArrayBuffer: + return true; + default: + return false; + } + } + + IndexingType indexingType() + { + ASSERT(hasIndexingType()); + if (op() == NewArrayBuffer) + return newArrayBufferData()->indexingType; + return m_opInfo; + } + + void setIndexingType(IndexingType indexingType) + { + ASSERT(hasIndexingType()); + m_opInfo = indexingType; + } + bool hasRegexpIndex() { return op() == NewRegexp; @@ -922,16 +949,36 @@ struct Node { return isInt32Speculation(prediction()); } + bool shouldSpeculateIntegerForArithmetic() + { + return isInt32SpeculationForArithmetic(prediction()); + } + + bool shouldSpeculateIntegerExpectingDefined() + { + return isInt32SpeculationExpectingDefined(prediction()); + } + bool shouldSpeculateDouble() { return isDoubleSpeculation(prediction()); } + bool shouldSpeculateDoubleForArithmetic() + { + return isDoubleSpeculationForArithmetic(prediction()); + } + bool shouldSpeculateNumber() { return isNumberSpeculation(prediction()); } + bool shouldSpeculateNumberExpectingDefined() + { + return isNumberSpeculationExpectingDefined(prediction()); + } + bool shouldSpeculateBoolean() { return isBooleanSpeculation(prediction()); @@ -1037,11 +1084,31 @@ struct Node { return op1.shouldSpeculateInteger() && op2.shouldSpeculateInteger(); } + static bool shouldSpeculateIntegerForArithmetic(Node& op1, Node& op2) + { + return op1.shouldSpeculateIntegerForArithmetic() && op2.shouldSpeculateIntegerForArithmetic(); + } + + static bool shouldSpeculateIntegerExpectingDefined(Node& op1, Node& op2) + { + return op1.shouldSpeculateIntegerExpectingDefined() && op2.shouldSpeculateIntegerExpectingDefined(); + } + + static bool shouldSpeculateDoubleForArithmetic(Node& op1, Node& op2) + { + return op1.shouldSpeculateDoubleForArithmetic() && op2.shouldSpeculateDoubleForArithmetic(); + } + static bool shouldSpeculateNumber(Node& op1, Node& op2) { return op1.shouldSpeculateNumber() && op2.shouldSpeculateNumber(); } + static bool shouldSpeculateNumberExpectingDefined(Node& op1, Node& op2) + { + return op1.shouldSpeculateNumberExpectingDefined() && op2.shouldSpeculateNumberExpectingDefined(); + } + static bool shouldSpeculateFinalObject(Node& op1, Node& op2) { return op1.shouldSpeculateFinalObject() && op2.shouldSpeculateFinalObject(); diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index 0e45e230c..8356d22f9 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -27,9 +27,9 @@ #include "DFGOperations.h" #include "Arguments.h" -#include "ButterflyInlineMethods.h" +#include "ButterflyInlines.h" #include "CodeBlock.h" -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "DFGOSRExit.h" #include "DFGRepatch.h" #include "DFGThunks.h" @@ -580,6 +580,40 @@ void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot); } +void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, double value) +{ + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + + JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value); + + if (index >= 0) { + array->putByIndexInline(exec, index, jsValue, true); + return; + } + + PutPropertySlot slot(true); + array->methodTable()->put( + array, exec, Identifier::from(exec, index), jsValue, slot); +} + +void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, double value) +{ + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + + JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value); + + if (index >= 0) { + array->putByIndexInline(exec, index, jsValue, false); + return; + } + + PutPropertySlot slot(false); + array->methodTable()->put( + array, exec, Identifier::from(exec, index), jsValue, slot); +} + EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array) { JSGlobalData* globalData = &exec->globalData(); @@ -589,6 +623,15 @@ EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue return JSValue::encode(jsNumber(array->length())); } +EncodedJSValue DFG_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array) +{ + JSGlobalData* globalData = &exec->globalData(); + NativeCallFrameTracer tracer(globalData, exec); + + array->push(exec, JSValue(JSValue::EncodeAsDouble, value)); + return JSValue::encode(jsNumber(array->length())); +} + EncodedJSValue DFG_OPERATION operationArrayPop(ExecState* exec, JSArray* array) { JSGlobalData* globalData = &exec->globalData(); @@ -1327,30 +1370,36 @@ char* DFG_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState* return reinterpret_cast<char*>(result); } -char* DFG_OPERATION operationEnsureContiguous(ExecState* exec, JSObject* object) +char* DFG_OPERATION operationEnsureInt32(ExecState* exec, JSObject* object) { JSGlobalData& globalData = exec->globalData(); NativeCallFrameTracer tracer(&globalData, exec); - return reinterpret_cast<char*>(object->ensureContiguous(globalData)); + return reinterpret_cast<char*>(object->ensureInt32(globalData)); } -char* DFG_OPERATION operationEnsureArrayStorage(ExecState* exec, JSObject* object) +char* DFG_OPERATION operationEnsureDouble(ExecState* exec, JSObject* object) { JSGlobalData& globalData = exec->globalData(); NativeCallFrameTracer tracer(&globalData, exec); + + return reinterpret_cast<char*>(object->ensureDouble(globalData)); +} - return reinterpret_cast<char*>(object->ensureArrayStorage(globalData)); +char* DFG_OPERATION operationEnsureContiguous(ExecState* exec, JSObject* object) +{ + JSGlobalData& globalData = exec->globalData(); + NativeCallFrameTracer tracer(&globalData, exec); + + return reinterpret_cast<char*>(object->ensureContiguous(globalData)); } -char* DFG_OPERATION operationEnsureContiguousOrArrayStorage(ExecState* exec, JSObject* object, int32_t index) +char* DFG_OPERATION operationEnsureArrayStorage(ExecState* exec, JSObject* object) { JSGlobalData& globalData = exec->globalData(); NativeCallFrameTracer tracer(&globalData, exec); - if (static_cast<unsigned>(index) >= MIN_SPARSE_ARRAY_INDEX) - return reinterpret_cast<char*>(object->ensureArrayStorage(globalData)); - return reinterpret_cast<char*>(object->ensureIndexedStorage(globalData)); + return reinterpret_cast<char*>(object->ensureArrayStorage(globalData)); } double DFG_OPERATION operationFModOnInts(int32_t a, int32_t b) diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h index 8d2beacec..b99c214e9 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.h +++ b/Source/JavaScriptCore/dfg/DFGOperations.h @@ -64,6 +64,7 @@ typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EAZ)(ExecState*, JSArray*, typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECI)(ExecState*, JSCell*, Identifier*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue); +typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EDA)(ExecState*, double, JSArray*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EGriJsgI)(ExecState*, ResolveOperation*, JSGlobalObject*, Identifier*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EI)(ExecState*, Identifier*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EIRo)(ExecState*, Identifier*, ResolveOperations*); @@ -92,6 +93,7 @@ typedef size_t DFG_OPERATION (*S_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*) typedef size_t DFG_OPERATION (*S_DFGOperation_EJ)(ExecState*, EncodedJSValue); typedef size_t DFG_OPERATION (*S_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue); typedef size_t DFG_OPERATION (*S_DFGOperation_J)(EncodedJSValue); +typedef void DFG_OPERATION (*V_DFGOperation_EOZD)(ExecState*, JSObject*, int32_t, double); typedef void DFG_OPERATION (*V_DFGOperation_EOZJ)(ExecState*, JSObject*, int32_t, EncodedJSValue); typedef void DFG_OPERATION (*V_DFGOperation_EC)(ExecState*, JSCell*); typedef void DFG_OPERATION (*V_DFGOperation_ECIcf)(ExecState*, JSCell*, InlineCallFrame*); @@ -148,7 +150,10 @@ void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSVal void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL; void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL; void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL; +void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL; +void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationArrayPushDouble(ExecState*, double value, JSArray*) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationArrayPopAndRecoverLength(ExecState*, JSArray*) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState*, JSCell*, JSCell*) WTF_INTERNAL; @@ -195,9 +200,10 @@ char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecStat char* DFG_OPERATION operationAllocatePropertyStorage(ExecState*, size_t newSize) WTF_INTERNAL; char* DFG_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState*, JSObject*) WTF_INTERNAL; char* DFG_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState*, JSObject*, size_t newSize) WTF_INTERNAL; +char* DFG_OPERATION operationEnsureInt32(ExecState*, JSObject*); +char* DFG_OPERATION operationEnsureDouble(ExecState*, JSObject*); char* DFG_OPERATION operationEnsureContiguous(ExecState*, JSObject*); char* DFG_OPERATION operationEnsureArrayStorage(ExecState*, JSObject*); -char* DFG_OPERATION operationEnsureContiguousOrArrayStorage(ExecState*, JSObject*, int32_t); // This method is used to lookup an exception hander, keyed by faultLocation, which is // the return location from one of the calls out to one of the helper operations above. diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index 3e8ead5c6..b5fde4eee 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -225,24 +225,6 @@ private: break; } - case ArithMod: { - SpeculatedType left = m_graph[node.child1()].prediction(); - SpeculatedType right = m_graph[node.child2()].prediction(); - - if (left && right) { - if (isInt32Speculation(mergeSpeculations(left, right)) - && nodeCanSpeculateInteger(node.arithNodeFlags())) - changed |= mergePrediction(SpecInt32); - else - changed |= mergePrediction(SpecDouble); - } - - flags |= NodeUsedAsValue; - changed |= m_graph[node.child1()].mergeFlags(flags); - changed |= m_graph[node.child2()].mergeFlags(flags); - break; - } - case UInt32ToNumber: { if (nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(SpecInt32); @@ -258,7 +240,7 @@ private: SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isNumberSpeculation(left) && isNumberSpeculation(right)) { + if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)) { if (m_graph.addShouldSpeculateInteger(node)) changed |= mergePrediction(SpecInt32); else @@ -333,7 +315,7 @@ private: SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isInt32Speculation(mergeSpeculations(left, right)) + if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) && nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(SpecInt32); else @@ -373,7 +355,7 @@ private: SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isInt32Speculation(mergeSpeculations(left, right)) + if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) && nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(SpecInt32); else @@ -382,7 +364,7 @@ private: // As soon as a multiply happens, we can easily end up in the part // of the double domain where the point at which you do truncation - // can change the outcome. So, ArithMul always checks for overflow + // can change the outcome. So, ArithDiv always checks for overflow // no matter what, and always forces its inputs to check as well. flags |= NodeUsedAsNumber | NodeNeedsNegZero; @@ -391,6 +373,24 @@ private: break; } + case ArithMod: { + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); + + if (left && right) { + if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) + && nodeCanSpeculateInteger(node.arithNodeFlags())) + changed |= mergePrediction(SpecInt32); + else + changed |= mergePrediction(SpecDouble); + } + + flags |= NodeUsedAsValue; + changed |= m_graph[node.child1()].mergeFlags(flags); + changed |= m_graph[node.child2()].mergeFlags(flags); + break; + } + case ArithSqrt: { changed |= setPrediction(SpecDouble); changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue); @@ -399,10 +399,11 @@ private: case ArithAbs: { SpeculatedType child = m_graph[node.child1()].prediction(); - if (nodeCanSpeculateInteger(node.arithNodeFlags())) - changed |= mergePrediction(child); + if (isInt32SpeculationForArithmetic(child) + && nodeCanSpeculateInteger(node.arithNodeFlags())) + changed |= mergePrediction(SpecInt32); else - changed |= setPrediction(speculatedDoubleTypeForPrediction(child)); + changed |= mergePrediction(speculatedDoubleTypeForPrediction(child)); flags &= ~NodeNeedsNegZero; changed |= m_graph[node.child1()].mergeFlags(flags); @@ -776,7 +777,7 @@ private: DoubleBallot ballot; - if (isNumberSpeculation(left) && isNumberSpeculation(right) + if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right) && !m_graph.addShouldSpeculateInteger(node)) ballot = VoteDouble; else @@ -814,7 +815,7 @@ private: DoubleBallot ballot; if (isNumberSpeculation(left) && isNumberSpeculation(right) - && !(Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child1()]) + && !(Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child1()]) && node.canSpeculateInteger())) ballot = VoteDouble; else @@ -827,7 +828,7 @@ private: case ArithAbs: DoubleBallot ballot; - if (!(m_graph[node.child1()].shouldSpeculateInteger() + if (!(m_graph[node.child1()].shouldSpeculateIntegerForArithmetic() && node.canSpeculateInteger())) ballot = VoteDouble; else @@ -849,6 +850,24 @@ private: break; } + case PutByVal: + case PutByValAlias: { + Edge child1 = m_graph.varArgChild(node, 0); + Edge child2 = m_graph.varArgChild(node, 1); + Edge child3 = m_graph.varArgChild(node, 2); + m_graph.vote(child1, VoteValue); + m_graph.vote(child2, VoteValue); + switch (node.arrayMode().type()) { + case Array::Double: + m_graph.vote(child3, VoteDouble); + break; + default: + m_graph.vote(child3, VoteValue); + break; + } + break; + } + default: m_graph.vote(node, VoteValue); break; diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 6bedd6d68..829bc14ff 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -59,7 +59,7 @@ SpeculativeJIT::~SpeculativeJIT() void SpeculativeJIT::emitAllocateJSArray(Structure* structure, GPRReg resultGPR, GPRReg storageGPR, unsigned numElements) { - ASSERT(hasContiguous(structure->indexingType())); + ASSERT(hasUndecided(structure->indexingType()) || hasInt32(structure->indexingType()) || hasDouble(structure->indexingType()) || hasContiguous(structure->indexingType())); GPRTemporary scratch(this); GPRReg scratchGPR = scratch.gpr(); @@ -67,6 +67,7 @@ void SpeculativeJIT::emitAllocateJSArray(Structure* structure, GPRReg resultGPR, unsigned vectorLength = std::max(BASE_VECTOR_LEN, numElements); JITCompiler::JumpList slowCases; + slowCases.append( emitAllocateBasicStorage(TrustedImm32(vectorLength * sizeof(JSValue) + sizeof(IndexingHeader)), storageGPR)); m_jit.subPtr(TrustedImm32(vectorLength * sizeof(JSValue)), storageGPR); @@ -79,6 +80,21 @@ void SpeculativeJIT::emitAllocateJSArray(Structure* structure, GPRReg resultGPR, m_jit.store32(TrustedImm32(numElements), MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); m_jit.store32(TrustedImm32(vectorLength), MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength())); + if (hasDouble(structure->indexingType()) && numElements < vectorLength) { +#if USE(JSVALUE64) + m_jit.move(TrustedImm64(bitwise_cast<int64_t>(QNaN)), scratchGPR); + for (unsigned i = numElements; i < vectorLength; ++i) + m_jit.store64(scratchGPR, MacroAssembler::Address(storageGPR, sizeof(double) * i)); +#else + EncodedValueDescriptor value; + value.asInt64 = JSValue::encode(JSValue(JSValue::EncodeAsDouble, QNaN)); + for (unsigned i = numElements; i < vectorLength; ++i) { + m_jit.store32(TrustedImm32(value.asBits.tag), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(TrustedImm32(value.asBits.payload), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + } +#endif + } + // I want a slow path that also loads out the storage pointer, and that's // what this custom CallArrayAllocatorSlowPathGenerator gives me. It's a lot // of work for a very small piece of functionality. :-/ @@ -343,24 +359,31 @@ const TypedArrayDescriptor* SpeculativeJIT::typedArrayDescriptor(ArrayMode array } } +JITCompiler::Jump SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode, IndexingType shape, bool invert) +{ + if (arrayMode.isJSArray()) { + m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR); + return m_jit.branch32( + invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | shape)); + } + m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR); + return m_jit.branch32(invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape)); +} + JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode, bool invert) { JITCompiler::JumpList result; switch (arrayMode.type()) { - case Array::Contiguous: { - if (arrayMode.isJSArray()) { - m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR); - result.append( - m_jit.branch32( - invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | ContiguousShape))); - break; - } - m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR); - result.append( - m_jit.branch32(invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(ContiguousShape))); - break; - } + case Array::Int32: + return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, Int32Shape, invert); + + case Array::Double: + return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, DoubleShape, invert); + + case Array::Contiguous: + return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, ContiguousShape, invert); + case Array::ArrayStorage: case Array::SlowPutArrayStorage: { if (arrayMode.isJSArray()) { @@ -437,6 +460,8 @@ void SpeculativeJIT::checkArray(Node& node) case Array::String: expectedClassInfo = &JSString::s_info; break; + case Array::Int32: + case Array::Double: case Array::Contiguous: case Array::ArrayStorage: case Array::SlowPutArrayStorage: { @@ -528,16 +553,30 @@ void SpeculativeJIT::arrayify(Node& node, GPRReg baseReg, GPRReg propertyReg) // If we're allegedly creating contiguous storage and the index is bogus, then // just don't. - if (node.arrayMode().type() == Array::Contiguous && propertyReg != InvalidGPRReg) { - speculationCheck( - Uncountable, JSValueRegs(), NoNode, - m_jit.branch32( - MacroAssembler::AboveOrEqual, propertyReg, TrustedImm32(MIN_SPARSE_ARRAY_INDEX))); + if (propertyReg != InvalidGPRReg) { + switch (node.arrayMode().type()) { + case Array::Int32: + case Array::Double: + case Array::Contiguous: + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branch32( + MacroAssembler::AboveOrEqual, propertyReg, TrustedImm32(MIN_SPARSE_ARRAY_INDEX))); + break; + default: + break; + } } // Now call out to create the array storage. silentSpillAllRegisters(tempGPR); switch (node.arrayMode().type()) { + case Array::Int32: + callOperation(operationEnsureInt32, tempGPR, baseReg); + break; + case Array::Double: + callOperation(operationEnsureDouble, tempGPR, baseReg); + break; case Array::Contiguous: callOperation(operationEnsureContiguous, tempGPR, baseReg); break; @@ -1797,6 +1836,85 @@ ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSo return ValueRecovery(); } +void SpeculativeJIT::compileDoublePutByVal(Node& node, SpeculateCellOperand& base, SpeculateStrictInt32Operand& property) +{ + Edge child3 = m_jit.graph().varArgChild(node, 2); + Edge child4 = m_jit.graph().varArgChild(node, 3); + + ArrayMode arrayMode = node.arrayMode(); + + GPRReg baseReg = base.gpr(); + GPRReg propertyReg = property.gpr(); + + SpeculateDoubleOperand value(this, child3); + + FPRReg valueReg = value.fpr(); + + if (!isRealNumberSpeculation(m_state.forNode(child3).m_type)) { + // FIXME: We need a way of profiling these, and we need to hoist them into + // SpeculateDoubleOperand. + speculationCheck( + BadType, JSValueRegs(), NoNode, + m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueReg, valueReg)); + } + + if (!m_compileOkay) + return; + + StorageOperand storage(this, child4); + GPRReg storageReg = storage.gpr(); + + if (node.op() == PutByValAlias) { + // Store the value to the array. + GPRReg propertyReg = property.gpr(); + FPRReg valueReg = value.fpr(); + m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight)); + + noResult(m_compileIndex); + return; + } + + GPRTemporary temporary; + GPRReg temporaryReg = temporaryRegisterForPutByVal(temporary, node); + + MacroAssembler::JumpList slowCases; + + if (arrayMode.isInBounds()) { + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); + } else { + MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())); + + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength()))); + + if (!arrayMode.isOutOfBounds()) + speculationCheck(Uncountable, JSValueRegs(), NoNode, slowCases); + + m_jit.add32(TrustedImm32(1), propertyReg, temporaryReg); + m_jit.store32(temporaryReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())); + + inBounds.link(&m_jit); + } + + m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight)); + + base.use(); + property.use(); + value.use(); + storage.use(); + + if (arrayMode.isOutOfBounds()) { + addSlowPathGenerator( + slowPathCall( + slowCases, this, + m_jit.codeBlock()->isStrictMode() ? operationPutDoubleByValBeyondArrayBoundsStrict : operationPutDoubleByValBeyondArrayBoundsNonStrict, + NoResult, baseReg, propertyReg, valueReg)); + } + + noResult(m_compileIndex, UseChildrenCalledExplicitly); +} + void SpeculativeJIT::compileGetCharCodeAt(Node& node) { SpeculateCellOperand string(this, node.child1()); @@ -2763,7 +2881,7 @@ void SpeculativeJIT::compileAdd(Node& node) return; } - if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) { + if (Node::shouldSpeculateNumberExpectingDefined(at(node.child1()), at(node.child2()))) { SpeculateDoubleOperand op1(this, node.child1()); SpeculateDoubleOperand op2(this, node.child2()); FPRTemporary result(this, op1, op2); @@ -3001,7 +3119,7 @@ void SpeculativeJIT::compileIntegerArithDivForX86(Node& node) void SpeculativeJIT::compileArithMod(Node& node) { - if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) + if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { compileSoftModulo(node); return; @@ -3336,6 +3454,8 @@ void SpeculativeJIT::compileGetArrayLength(Node& node) const TypedArrayDescriptor* descriptor = typedArrayDescriptor(node.arrayMode()); switch (node.arrayMode().type()) { + case Array::Int32: + case Array::Double: case Array::Contiguous: { StorageOperand storage(this, node.child2()); GPRTemporary result(this, storage); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 446ea7dbe..059d3a6c6 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -1308,6 +1308,11 @@ public: m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(J_DFGOperation_EDA operation, GPRReg result, FPRReg arg1, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(arg1, arg2); + return appendCallWithExceptionCheckSetResult(operation, result); + } JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg result, GPRReg arg1, GPRReg arg2) { m_jit.setupArgumentsWithExecState(arg1, arg2); @@ -1453,6 +1458,11 @@ public: m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); return appendCallWithExceptionCheck(operation); } + JITCompiler::Call callOperation(V_DFGOperation_EOZD operation, GPRReg arg1, GPRReg arg2, FPRReg arg3) + { + m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); + return appendCallWithExceptionCheck(operation); + } JITCompiler::Call callOperation(V_DFGOperation_EOZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3) { m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); @@ -1661,11 +1671,21 @@ public: m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, TrustedImm32(arg1Tag), TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } + JITCompiler::Call callOperation(J_DFGOperation_EDA operation, GPRReg resultTag, GPRReg resultPayload, FPRReg arg1, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(arg1, arg2); + return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); + } JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2) { m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } + JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg resultTag, GPRReg resultPayload, TrustedImm32 arg1Tag, GPRReg arg1Payload, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2); + return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); + } JITCompiler::Call callOperation(J_DFGOperation_EJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload) { m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag); @@ -1819,11 +1839,21 @@ public: m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag); return appendCallWithExceptionCheck(operation); } + JITCompiler::Call callOperation(V_DFGOperation_EOZD operation, GPRReg arg1, GPRReg arg2, FPRReg arg3) + { + m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); + return appendCallWithExceptionCheck(operation); + } JITCompiler::Call callOperation(V_DFGOperation_EOZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3Tag, GPRReg arg3Payload) { m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag); return appendCallWithExceptionCheck(operation); } + JITCompiler::Call callOperation(V_DFGOperation_EOZJ operation, GPRReg arg1, GPRReg arg2, TrustedImm32 arg3Tag, GPRReg arg3Payload) + { + m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag); + return appendCallWithExceptionCheck(operation); + } JITCompiler::Call callOperation(V_DFGOperation_W operation, WatchpointSet* watchpointSet) { m_jit.setupArguments(TrustedImmPtr(watchpointSet)); @@ -2270,6 +2300,11 @@ public: void compileAllocatePropertyStorage(Node&); void compileReallocatePropertyStorage(Node&); +#if USE(JSVALUE32_64) + template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType> + void compileContiguousPutByVal(Node&, BaseOperandType&, PropertyOperandType&, ValueOperandType&, GPRReg valuePayloadReg, TagType valueTag); +#endif + void compileDoublePutByVal(Node&, SpeculateCellOperand& base, SpeculateStrictInt32Operand& property); bool putByValWillNeedExtraRegister(ArrayMode arrayMode) { return arrayMode.mayStoreToHole(); @@ -2415,6 +2450,7 @@ public: const TypedArrayDescriptor* typedArrayDescriptor(ArrayMode); + JITCompiler::Jump jumpSlowForUnwantedArrayMode(GPRReg tempWithIndexingTypeReg, ArrayMode, IndexingType, bool invert); JITCompiler::JumpList jumpSlowForUnwantedArrayMode(GPRReg tempWithIndexingTypeReg, ArrayMode, bool invert = false); void checkArray(Node&); void arrayify(Node&, GPRReg baseReg, GPRReg propertyReg); @@ -2955,6 +2991,11 @@ public: m_gprOrInvalid = m_jit->fillSpeculateInt(index(), m_format); return m_gprOrInvalid; } + + void use() + { + m_jit->use(m_index); + } private: SpeculativeJIT* m_jit; @@ -3035,6 +3076,11 @@ public: m_fprOrInvalid = m_jit->fillSpeculateDouble(index()); return m_fprOrInvalid; } + + void use() + { + m_jit->use(m_index); + } private: SpeculativeJIT* m_jit; diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 65fdf5593..694f1452e 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -2046,6 +2046,69 @@ void SpeculativeJIT::emitBranch(Node& node) } } +template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType> +void SpeculativeJIT::compileContiguousPutByVal(Node& node, BaseOperandType& base, PropertyOperandType& property, ValueOperandType& value, GPRReg valuePayloadReg, TagType valueTag) +{ + Edge child4 = m_jit.graph().varArgChild(node, 3); + + ArrayMode arrayMode = node.arrayMode(); + + GPRReg baseReg = base.gpr(); + GPRReg propertyReg = property.gpr(); + + StorageOperand storage(this, child4); + GPRReg storageReg = storage.gpr(); + + if (node.op() == PutByValAlias) { + // Store the value to the array. + GPRReg propertyReg = property.gpr(); + m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + + noResult(m_compileIndex); + return; + } + + MacroAssembler::JumpList slowCases; + + if (arrayMode.isInBounds()) { + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); + } else { + MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())); + + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength()))); + + if (!arrayMode.isOutOfBounds()) + speculationCheck(Uncountable, JSValueRegs(), NoNode, slowCases); + + m_jit.add32(TrustedImm32(1), propertyReg); + m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())); + m_jit.sub32(TrustedImm32(1), propertyReg); + + inBounds.link(&m_jit); + } + + m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + + base.use(); + property.use(); + value.use(); + storage.use(); + + if (arrayMode.isOutOfBounds()) { + addSlowPathGenerator( + slowPathCall( + slowCases, this, + m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, + NoResult, baseReg, propertyReg, valueTag, valuePayloadReg)); + } + + noResult(m_compileIndex, UseChildrenCalledExplicitly); +} + void SpeculativeJIT::compile(Node& node) { NodeType op = node.op(); @@ -2366,7 +2429,8 @@ void SpeculativeJIT::compile(Node& node) break; case ArithDiv: { - if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { + if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2())) + && node.canSpeculateInteger()) { #if CPU(X86) compileIntegerArithDivForX86(node); #else // CPU(X86) -> so non-X86 code follows @@ -2393,7 +2457,8 @@ void SpeculativeJIT::compile(Node& node) } case ArithAbs: { - if (at(node.child1()).shouldSpeculateInteger() && node.canSpeculateInteger()) { + if (at(node.child1()).shouldSpeculateIntegerForArithmetic() + && node.canSpeculateInteger()) { SpeculateIntegerOperand op1(this, node.child1()); GPRTemporary result(this, op1); GPRTemporary scratch(this); @@ -2417,7 +2482,8 @@ void SpeculativeJIT::compile(Node& node) case ArithMin: case ArithMax: { - if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { + if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2())) + && node.canSpeculateInteger()) { SpeculateStrictInt32Operand op1(this, node.child1()); SpeculateStrictInt32Operand op2(this, node.child2()); GPRTemporary result(this, op1); @@ -2567,6 +2633,7 @@ void SpeculativeJIT::compile(Node& node) jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex); break; } + case Array::Int32: case Array::Contiguous: { if (node.arrayMode().isInBounds()) { SpeculateStrictInt32Operand property(this, node.child2()); @@ -2580,8 +2647,20 @@ void SpeculativeJIT::compile(Node& node) speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); - GPRTemporary resultTag(this); GPRTemporary resultPayload(this); + if (node.arrayMode().type() == Array::Int32) { + speculationCheck( + OutOfBounds, JSValueRegs(), NoNode, + m_jit.branch32( + MacroAssembler::Equal, + MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), + TrustedImm32(JSValue::EmptyValueTag))); + m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr()); + integerResult(resultPayload.gpr(), m_compileIndex); + break; + } + + GPRTemporary resultTag(this); m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr()); speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag))); m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr()); @@ -2621,6 +2700,60 @@ void SpeculativeJIT::compile(Node& node) jsValueResult(resultTagReg, resultPayloadReg, m_compileIndex); break; } + case Array::Double: { + if (node.arrayMode().isInBounds()) { + SpeculateStrictInt32Operand property(this, node.child2()); + StorageOperand storage(this, node.child3()); + + GPRReg propertyReg = property.gpr(); + GPRReg storageReg = storage.gpr(); + + if (!m_compileOkay) + return; + + speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); + + FPRTemporary result(this); + m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr()); + speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr())); + doubleResult(result.fpr(), m_compileIndex); + break; + } + + SpeculateCellOperand base(this, node.child1()); + SpeculateStrictInt32Operand property(this, node.child2()); + StorageOperand storage(this, node.child3()); + + GPRReg baseReg = base.gpr(); + GPRReg propertyReg = property.gpr(); + GPRReg storageReg = storage.gpr(); + + if (!m_compileOkay) + return; + + GPRTemporary resultTag(this); + GPRTemporary resultPayload(this); + FPRTemporary temp(this); + GPRReg resultTagReg = resultTag.gpr(); + GPRReg resultPayloadReg = resultPayload.gpr(); + FPRReg tempReg = temp.fpr(); + + MacroAssembler::JumpList slowCases; + + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); + + m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg); + slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempReg, tempReg)); + boxDouble(tempReg, resultTagReg, resultPayloadReg); + + addSlowPathGenerator( + slowPathCall( + slowCases, this, operationGetByValArrayInt, + JSValueRegs(resultTagReg, resultPayloadReg), baseReg, propertyReg)); + + jsValueResult(resultTagReg, resultPayloadReg, m_compileIndex); + break; + } case Array::ArrayStorage: case Array::SlowPutArrayStorage: { if (node.arrayMode().isInBounds()) { @@ -2771,6 +2904,17 @@ void SpeculativeJIT::compile(Node& node) GPRReg propertyReg = property.gpr(); switch (arrayMode.type()) { + case Array::Int32: { + SpeculateIntegerOperand value(this, child3); + + GPRReg valuePayloadReg = value.gpr(); + + if (!m_compileOkay) + return; + + compileContiguousPutByVal(node, base, property, value, valuePayloadReg, TrustedImm32(JSValue::Int32Tag)); + break; + } case Array::Contiguous: { JSValueOperand value(this, child3); @@ -2784,61 +2928,14 @@ void SpeculativeJIT::compile(Node& node) GPRTemporary scratch(this); writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratch.gpr()); } - - StorageOperand storage(this, child4); - GPRReg storageReg = storage.gpr(); - - if (node.op() == PutByValAlias) { - // Store the value to the array. - GPRReg propertyReg = property.gpr(); - m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); - m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); - - noResult(m_compileIndex); - break; - } - - MacroAssembler::JumpList slowCases; - - if (arrayMode.isInBounds()) { - speculationCheck( - Uncountable, JSValueRegs(), NoNode, - m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); - } else { - MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())); - - slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength()))); - - if (!arrayMode.isOutOfBounds()) - speculationCheck(Uncountable, JSValueRegs(), NoNode, slowCases); - - m_jit.add32(TrustedImm32(1), propertyReg); - m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())); - m_jit.sub32(TrustedImm32(1), propertyReg); - - inBounds.link(&m_jit); - } - - m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); - m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); - - base.use(); - property.use(); - value.use(); - storage.use(); - if (arrayMode.isOutOfBounds()) { - addSlowPathGenerator( - slowPathCall( - slowCases, this, - m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, - NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg)); - } - - noResult(m_compileIndex, UseChildrenCalledExplicitly); + compileContiguousPutByVal(node, base, property, value, valuePayloadReg, valueTagReg); + break; + } + case Array::Double: { + compileDoublePutByVal(node, base, property); break; } - case Array::ArrayStorage: case Array::SlowPutArrayStorage: { JSValueOperand value(this, child3); @@ -3028,24 +3125,47 @@ void SpeculativeJIT::compile(Node& node) ASSERT(node.arrayMode().isJSArray()); SpeculateCellOperand base(this, node.child1()); - JSValueOperand value(this, node.child2()); GPRTemporary storageLength(this); GPRReg baseGPR = base.gpr(); - GPRReg valueTagGPR = value.tagGPR(); - GPRReg valuePayloadGPR = value.payloadGPR(); GPRReg storageLengthGPR = storageLength.gpr(); - if (Heap::isWriteBarrierEnabled()) { - GPRTemporary scratch(this); - writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR); - } - StorageOperand storage(this, node.child3()); GPRReg storageGPR = storage.gpr(); switch (node.arrayMode().type()) { + case Array::Int32: { + SpeculateIntegerOperand value(this, node.child2()); + GPRReg valuePayloadGPR = value.gpr(); + + m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR); + MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength())); + m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + m_jit.add32(TrustedImm32(1), storageLengthGPR); + m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); + m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR); + + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationArrayPush, + JSValueRegs(storageGPR, storageLengthGPR), + TrustedImm32(JSValue::Int32Tag), valuePayloadGPR, baseGPR)); + + jsValueResult(storageGPR, storageLengthGPR, m_compileIndex); + break; + } + case Array::Contiguous: { + JSValueOperand value(this, node.child2()); + GPRReg valueTagGPR = value.tagGPR(); + GPRReg valuePayloadGPR = value.payloadGPR(); + + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR); + } + m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR); MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength())); m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); @@ -3064,7 +3184,45 @@ void SpeculativeJIT::compile(Node& node) break; } + case Array::Double: { + SpeculateDoubleOperand value(this, node.child2()); + FPRReg valueFPR = value.fpr(); + + if (!isRealNumberSpeculation(m_state.forNode(node.child2()).m_type)) { + // FIXME: We need a way of profiling these, and we need to hoist them into + // SpeculateDoubleOperand. + speculationCheck( + BadType, JSValueRegs(), NoNode, + m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR)); + } + + m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR); + MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength())); + m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight)); + m_jit.add32(TrustedImm32(1), storageLengthGPR); + m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); + m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR); + + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationArrayPushDouble, + JSValueRegs(storageGPR, storageLengthGPR), + valueFPR, baseGPR)); + + jsValueResult(storageGPR, storageLengthGPR, m_compileIndex); + break; + } + case Array::ArrayStorage: { + JSValueOperand value(this, node.child2()); + GPRReg valueTagGPR = value.tagGPR(); + GPRReg valuePayloadGPR = value.payloadGPR(); + + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR); + } + m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR); // Refuse to handle bizarre lengths. @@ -3107,6 +3265,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg storageGPR = storage.gpr(); switch (node.arrayMode().type()) { + case Array::Int32: case Array::Contiguous: { m_jit.load32( MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR); @@ -3140,6 +3299,44 @@ void SpeculativeJIT::compile(Node& node) break; } + case Array::Double: { + FPRTemporary temp(this); + FPRReg tempFPR = temp.fpr(); + + m_jit.load32( + MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR); + MacroAssembler::Jump undefinedCase = + m_jit.branchTest32(MacroAssembler::Zero, valuePayloadGPR); + m_jit.sub32(TrustedImm32(1), valuePayloadGPR); + m_jit.store32( + valuePayloadGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); + m_jit.loadDouble( + MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight), + tempFPR); + MacroAssembler::Jump slowCase = m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempFPR, tempFPR); + JSValue nan = JSValue(JSValue::EncodeAsDouble, QNaN); + m_jit.store32( + MacroAssembler::TrustedImm32(nan.u.asBits.tag), + MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32( + MacroAssembler::TrustedImm32(nan.u.asBits.payload), + MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + boxDouble(tempFPR, valueTagGPR, valuePayloadGPR); + + addSlowPathGenerator( + slowPathMove( + undefinedCase, this, + MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR, + MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR)); + addSlowPathGenerator( + slowPathCall( + slowCase, this, operationArrayPopAndRecoverLength, + JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR)); + + jsValueResult(valueTagGPR, valuePayloadGPR, m_compileIndex); + break; + } + case Array::ArrayStorage: { GPRTemporary storageLength(this); GPRReg storageLengthGPR = storageLength.gpr(); @@ -3358,11 +3555,17 @@ void SpeculativeJIT::compile(Node& node) case NewArray: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - if (!globalObject->isHavingABadTime()) { + if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) { globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); - ASSERT(hasContiguous(globalObject->arrayStructure()->indexingType())); - + Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()); + ASSERT(structure->indexingType() == node.indexingType()); + ASSERT( + hasUndecided(structure->indexingType()) + || hasInt32(structure->indexingType()) + || hasDouble(structure->indexingType()) + || hasContiguous(structure->indexingType())); + unsigned numElements = node.numChildren(); GPRTemporary result(this); @@ -3371,17 +3574,52 @@ void SpeculativeJIT::compile(Node& node) GPRReg resultGPR = result.gpr(); GPRReg storageGPR = storage.gpr(); - emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements); + emitAllocateJSArray(structure, resultGPR, storageGPR, numElements); // At this point, one way or another, resultGPR and storageGPR have pointers to // the JSArray and the Butterfly, respectively. + ASSERT(!hasUndecided(structure->indexingType()) || !node.numChildren()); + for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) { - JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]); - GPRReg opTagGPR = operand.tagGPR(); - GPRReg opPayloadGPR = operand.payloadGPR(); - m_jit.store32(opTagGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); - m_jit.store32(opPayloadGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]; + switch (node.indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: + CRASH(); + break; + case ALL_DOUBLE_INDEXING_TYPES: { + SpeculateDoubleOperand operand(this, use); + FPRReg opFPR = operand.fpr(); + if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) { + // FIXME: We need a way of profiling these, and we need to hoist them into + // SpeculateDoubleOperand. + speculationCheck( + BadType, JSValueRegs(), NoNode, + m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR)); + } + + m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx)); + break; + } + case ALL_INT32_INDEXING_TYPES: { + SpeculateIntegerOperand operand(this, use); + m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(operand.gpr(), MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + break; + } + case ALL_CONTIGUOUS_INDEXING_TYPES: { + JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]); + GPRReg opTagGPR = operand.tagGPR(); + GPRReg opPayloadGPR = operand.payloadGPR(); + m_jit.store32(opTagGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(opPayloadGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + break; + } + default: + CRASH(); + break; + } } // Yuck, we should *really* have a way of also returning the storageGPR. But @@ -3399,7 +3637,7 @@ void SpeculativeJIT::compile(Node& node) flushRegisters(); GPRResult result(this); callOperation( - operationNewEmptyArray, result.gpr(), globalObject->arrayStructure()); + operationNewEmptyArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())); cellResult(result.gpr(), m_compileIndex); break; } @@ -3409,13 +3647,61 @@ void SpeculativeJIT::compile(Node& node) EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0; for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) { - JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]); - GPRReg opTagGPR = operand.tagGPR(); - GPRReg opPayloadGPR = operand.payloadGPR(); - operand.use(); - - m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); - m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); + // Need to perform the speculations that this node promises to perform. If we're + // emitting code here and the indexing type is not array storage then there is + // probably something hilarious going on and we're already failing at all the + // things, but at least we're going to be sound. + Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]; + switch (node.indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: + CRASH(); + break; + case ALL_DOUBLE_INDEXING_TYPES: { + SpeculateDoubleOperand operand(this, use); + FPRReg opFPR = operand.fpr(); + if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) { + // FIXME: We need a way of profiling these, and we need to hoist them into + // SpeculateDoubleOperand. + speculationCheck( + BadType, JSValueRegs(), NoNode, + m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR)); + } + + m_jit.storeDouble(opFPR, reinterpret_cast<char*>(buffer + operandIdx)); + break; + } + case ALL_INT32_INDEXING_TYPES: { + SpeculateIntegerOperand operand(this, use); + GPRReg opGPR = operand.gpr(); + m_jit.store32(TrustedImm32(JSValue::Int32Tag), reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); + m_jit.store32(opGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); + break; + } + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { + JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]); + GPRReg opTagGPR = operand.tagGPR(); + GPRReg opPayloadGPR = operand.payloadGPR(); + + m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); + m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); + operand.use(); + break; + } + default: + CRASH(); + break; + } + } + + switch (node.indexingType()) { + case ALL_DOUBLE_INDEXING_TYPES: + case ALL_INT32_INDEXING_TYPES: + useChildren(node); + break; + default: + break; } flushRegisters(); @@ -3431,8 +3717,8 @@ void SpeculativeJIT::compile(Node& node) GPRResult result(this); callOperation( - operationNewArray, result.gpr(), globalObject->arrayStructure(), - static_cast<void *>(buffer), node.numChildren()); + operationNewArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), + static_cast<void*>(buffer), node.numChildren()); if (scratchSize) { GPRTemporary scratch(this); @@ -3471,17 +3757,30 @@ void SpeculativeJIT::compile(Node& node) emitAllocateBasicStorage(resultGPR, storageGPR)); m_jit.subPtr(scratchGPR, storageGPR); emitAllocateBasicJSObject<JSArray, MarkedBlock::None>( - TrustedImmPtr(globalObject->arrayStructure()), resultGPR, scratchGPR, + TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), resultGPR, scratchGPR, storageGPR, sizeof(JSArray), slowCases); m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength())); + if (hasDouble(node.indexingType())) { + JSValue nan = JSValue(JSValue::EncodeAsDouble, QNaN); + + m_jit.move(sizeGPR, scratchGPR); + MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR); + MacroAssembler::Label loop = m_jit.label(); + m_jit.sub32(TrustedImm32(1), scratchGPR); + m_jit.store32(TrustedImm32(nan.u.asBits.tag), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(TrustedImm32(nan.u.asBits.payload), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit); + done.link(&m_jit); + } + addSlowPathGenerator(adoptPtr( new CallArrayAllocatorWithVariableSizeSlowPathGenerator( slowCases, this, operationNewArrayWithSize, resultGPR, - globalObject->arrayStructure(), - globalObject->arrayStructureWithArrayStorage(), + globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), + globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage), sizeGPR))); cellResult(resultGPR, m_compileIndex); @@ -3492,15 +3791,24 @@ void SpeculativeJIT::compile(Node& node) GPRReg sizeGPR = size.gpr(); flushRegisters(); GPRResult result(this); + GPRReg resultGPR = result.gpr(); + GPRReg structureGPR = selectScratchGPR(sizeGPR); + MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)); + m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), structureGPR); + MacroAssembler::Jump done = m_jit.jump(); + bigLength.link(&m_jit); + m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)), structureGPR); + done.link(&m_jit); callOperation( - operationNewArrayWithSize, result.gpr(), globalObject->arrayStructure(), sizeGPR); - cellResult(result.gpr(), m_compileIndex); + operationNewArrayWithSize, resultGPR, structureGPR, sizeGPR); + cellResult(resultGPR, m_compileIndex); break; } case NewArrayBuffer: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - if (!globalObject->isHavingABadTime()) { + IndexingType indexingType = node.indexingType(); + if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) { globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); unsigned numElements = node.numConstants(); @@ -3511,12 +3819,25 @@ void SpeculativeJIT::compile(Node& node) GPRReg resultGPR = result.gpr(); GPRReg storageGPR = storage.gpr(); - emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements); + emitAllocateJSArray(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), resultGPR, storageGPR, numElements); - int32_t* data = bitwise_cast<int32_t*>(m_jit.codeBlock()->constantBuffer(node.startConstant())); - for (unsigned index = 0; index < node.numConstants() * 2; ++index) { - m_jit.store32( - Imm32(data[index]), MacroAssembler::Address(storageGPR, sizeof(int32_t) * index)); + if (node.indexingType() == ArrayWithDouble) { + JSValue* data = m_jit.codeBlock()->constantBuffer(node.startConstant()); + for (unsigned index = 0; index < node.numConstants(); ++index) { + union { + int32_t halves[2]; + double value; + } u; + u.value = data[index].asNumber(); + m_jit.store32(Imm32(u.halves[0]), MacroAssembler::Address(storageGPR, sizeof(double) * index)); + m_jit.store32(Imm32(u.halves[1]), MacroAssembler::Address(storageGPR, sizeof(double) * index + sizeof(int32_t))); + } + } else { + int32_t* data = bitwise_cast<int32_t*>(m_jit.codeBlock()->constantBuffer(node.startConstant())); + for (unsigned index = 0; index < node.numConstants() * 2; ++index) { + m_jit.store32( + Imm32(data[index]), MacroAssembler::Address(storageGPR, sizeof(int32_t) * index)); + } } cellResult(resultGPR, m_compileIndex); @@ -3526,7 +3847,7 @@ void SpeculativeJIT::compile(Node& node) flushRegisters(); GPRResult result(this); - callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructure(), node.startConstant(), node.numConstants()); + callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), node.startConstant(), node.numConstants()); cellResult(result.gpr(), m_compileIndex); break; diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index 6c066c388..ecd823e7b 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -2403,7 +2403,8 @@ void SpeculativeJIT::compile(Node& node) break; case ArithDiv: { - if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { + if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2())) + && node.canSpeculateInteger()) { compileIntegerArithDivForX86(node); break; } @@ -2426,7 +2427,8 @@ void SpeculativeJIT::compile(Node& node) } case ArithAbs: { - if (at(node.child1()).shouldSpeculateInteger() && node.canSpeculateInteger()) { + if (at(node.child1()).shouldSpeculateIntegerForArithmetic() + && node.canSpeculateInteger()) { SpeculateIntegerOperand op1(this, node.child1()); GPRTemporary result(this); GPRTemporary scratch(this); @@ -2450,7 +2452,8 @@ void SpeculativeJIT::compile(Node& node) case ArithMin: case ArithMax: { - if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { + if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2())) + && node.canSpeculateInteger()) { SpeculateStrictInt32Operand op1(this, node.child1()); SpeculateStrictInt32Operand op2(this, node.child2()); GPRTemporary result(this, op1); @@ -2598,6 +2601,7 @@ void SpeculativeJIT::compile(Node& node) jsValueResult(result.gpr(), m_compileIndex); break; } + case Array::Int32: case Array::Contiguous: { if (node.arrayMode().isInBounds()) { SpeculateStrictInt32Operand property(this, node.child2()); @@ -2614,7 +2618,7 @@ void SpeculativeJIT::compile(Node& node) GPRTemporary result(this); m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.gpr()); speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchTest64(MacroAssembler::Zero, result.gpr())); - jsValueResult(result.gpr(), m_compileIndex); + jsValueResult(result.gpr(), m_compileIndex, node.arrayMode().type() == Array::Int32 ? DataFormatJSInteger : DataFormatJS); break; } @@ -2647,6 +2651,60 @@ void SpeculativeJIT::compile(Node& node) jsValueResult(resultReg, m_compileIndex); break; } + + case Array::Double: { + if (node.arrayMode().isInBounds()) { + SpeculateStrictInt32Operand property(this, node.child2()); + StorageOperand storage(this, node.child3()); + + GPRReg propertyReg = property.gpr(); + GPRReg storageReg = storage.gpr(); + + if (!m_compileOkay) + return; + + speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); + + FPRTemporary result(this); + m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr()); + speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr())); + doubleResult(result.fpr(), m_compileIndex); + break; + } + + SpeculateCellOperand base(this, node.child1()); + SpeculateStrictInt32Operand property(this, node.child2()); + StorageOperand storage(this, node.child3()); + + GPRReg baseReg = base.gpr(); + GPRReg propertyReg = property.gpr(); + GPRReg storageReg = storage.gpr(); + + if (!m_compileOkay) + return; + + GPRTemporary result(this); + FPRTemporary temp(this); + GPRReg resultReg = result.gpr(); + FPRReg tempReg = temp.fpr(); + + MacroAssembler::JumpList slowCases; + + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); + + m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg); + slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempReg, tempReg)); + boxDouble(tempReg, resultReg); + + addSlowPathGenerator( + slowPathCall( + slowCases, this, operationGetByValArrayInt, + result.gpr(), baseReg, propertyReg)); + + jsValueResult(resultReg, m_compileIndex); + break; + } + case Array::ArrayStorage: case Array::SlowPutArrayStorage: { if (node.arrayMode().isInBounds()) { @@ -2789,6 +2847,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg propertyReg = property.gpr(); switch (arrayMode.type()) { + case Array::Int32: case Array::Contiguous: { JSValueOperand value(this, child3); @@ -2796,8 +2855,15 @@ void SpeculativeJIT::compile(Node& node) if (!m_compileOkay) return; + + if (arrayMode.type() == Array::Int32 + && !isInt32Speculation(m_state.forNode(child3).m_type)) { + speculationCheck( + BadType, JSValueRegs(valueReg), child3, + m_jit.branch64(MacroAssembler::Below, valueReg, GPRInfo::tagTypeNumberRegister)); + } - if (Heap::isWriteBarrierEnabled()) { + if (arrayMode.type() == Array::Contiguous && Heap::isWriteBarrierEnabled()) { GPRTemporary scratch(this); writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratch.gpr()); } @@ -2857,6 +2923,11 @@ void SpeculativeJIT::compile(Node& node) break; } + case Array::Double: { + compileDoublePutByVal(node, base, property); + break; + } + case Array::ArrayStorage: case Array::SlowPutArrayStorage: { JSValueOperand value(this, child3); @@ -3081,23 +3152,31 @@ void SpeculativeJIT::compile(Node& node) ASSERT(node.arrayMode().isJSArray()); SpeculateCellOperand base(this, node.child1()); - JSValueOperand value(this, node.child2()); GPRTemporary storageLength(this); GPRReg baseGPR = base.gpr(); - GPRReg valueGPR = value.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - if (Heap::isWriteBarrierEnabled()) { - GPRTemporary scratch(this); - writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR); - } - StorageOperand storage(this, node.child3()); GPRReg storageGPR = storage.gpr(); switch (node.arrayMode().type()) { + case Array::Int32: case Array::Contiguous: { + JSValueOperand value(this, node.child2()); + GPRReg valueGPR = value.gpr(); + + if (node.arrayMode().type() == Array::Int32 && !isInt32Speculation(m_state.forNode(node.child2()).m_type)) { + speculationCheck( + BadType, JSValueRegs(valueGPR), node.child2(), + m_jit.branch64(MacroAssembler::Below, valueGPR, GPRInfo::tagTypeNumberRegister)); + } + + if (node.arrayMode().type() != Array::Int32 && Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR); + } + m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR); MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength())); m_jit.store64(valueGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight)); @@ -3114,7 +3193,43 @@ void SpeculativeJIT::compile(Node& node) break; } + case Array::Double: { + SpeculateDoubleOperand value(this, node.child2()); + FPRReg valueFPR = value.fpr(); + + if (!isRealNumberSpeculation(m_state.forNode(node.child2()).m_type)) { + // FIXME: We need a way of profiling these, and we need to hoist them into + // SpeculateDoubleOperand. + speculationCheck( + BadType, JSValueRegs(), NoNode, + m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR)); + } + + m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR); + MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength())); + m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight)); + m_jit.add32(TrustedImm32(1), storageLengthGPR); + m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); + m_jit.or64(GPRInfo::tagTypeNumberRegister, storageLengthGPR); + + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationArrayPushDouble, NoResult, storageLengthGPR, + valueFPR, baseGPR)); + + jsValueResult(storageLengthGPR, m_compileIndex); + break; + } + case Array::ArrayStorage: { + JSValueOperand value(this, node.child2()); + GPRReg valueGPR = value.gpr(); + + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR); + } + m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR); // Refuse to handle bizarre lengths. @@ -3152,13 +3267,17 @@ void SpeculativeJIT::compile(Node& node) StorageOperand storage(this, node.child2()); GPRTemporary value(this); GPRTemporary storageLength(this); + FPRTemporary temp(this); // This is kind of lame, since we don't always need it. I'm relying on the fact that we don't have FPR pressure, especially in code that uses pop(). GPRReg baseGPR = base.gpr(); GPRReg storageGPR = storage.gpr(); GPRReg valueGPR = value.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); + FPRReg tempFPR = temp.fpr(); switch (node.arrayMode().type()) { + case Array::Int32: + case Array::Double: case Array::Contiguous: { m_jit.load32( MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR); @@ -3167,14 +3286,27 @@ void SpeculativeJIT::compile(Node& node) m_jit.sub32(TrustedImm32(1), storageLengthGPR); m_jit.store32( storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); - m_jit.load64( - MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight), - valueGPR); - // FIXME: This would not have to be here if changing the publicLength also zeroed the values between the old - // length and the new length. - m_jit.store64( + MacroAssembler::Jump slowCase; + if (node.arrayMode().type() == Array::Double) { + m_jit.loadDouble( + MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight), + tempFPR); + // FIXME: This would not have to be here if changing the publicLength also zeroed the values between the old + // length and the new length. + m_jit.store64( + MacroAssembler::TrustedImm64((int64_t)0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight)); + slowCase = m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempFPR, tempFPR); + boxDouble(tempFPR, valueGPR); + } else { + m_jit.load64( + MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight), + valueGPR); + // FIXME: This would not have to be here if changing the publicLength also zeroed the values between the old + // length and the new length. + m_jit.store64( MacroAssembler::TrustedImm64((int64_t)0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight)); - MacroAssembler::Jump slowCase = m_jit.branchTest64(MacroAssembler::Zero, valueGPR); + slowCase = m_jit.branchTest64(MacroAssembler::Zero, valueGPR); + } addSlowPathGenerator( slowPathMove( @@ -3184,6 +3316,7 @@ void SpeculativeJIT::compile(Node& node) slowPathCall( slowCase, this, operationArrayPopAndRecoverLength, valueGPR, baseGPR)); + // We can't know for sure that the result is an int because of the slow paths. :-/ jsValueResult(valueGPR, m_compileIndex); break; } @@ -3338,10 +3471,16 @@ void SpeculativeJIT::compile(Node& node) case NewArray: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - if (!globalObject->isHavingABadTime()) { + if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) { globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); - ASSERT(hasContiguous(globalObject->arrayStructure()->indexingType())); + Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()); + ASSERT(structure->indexingType() == node.indexingType()); + ASSERT( + hasUndecided(structure->indexingType()) + || hasInt32(structure->indexingType()) + || hasDouble(structure->indexingType()) + || hasContiguous(structure->indexingType())); unsigned numElements = node.numChildren(); @@ -3351,15 +3490,50 @@ void SpeculativeJIT::compile(Node& node) GPRReg resultGPR = result.gpr(); GPRReg storageGPR = storage.gpr(); - emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements); + emitAllocateJSArray(structure, resultGPR, storageGPR, numElements); // At this point, one way or another, resultGPR and storageGPR have pointers to // the JSArray and the Butterfly, respectively. + ASSERT(!hasUndecided(structure->indexingType()) || !node.numChildren()); + for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) { - JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]); - GPRReg opGPR = operand.gpr(); - m_jit.store64(opGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx)); + Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]; + switch (node.indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: + CRASH(); + break; + case ALL_DOUBLE_INDEXING_TYPES: { + SpeculateDoubleOperand operand(this, use); + FPRReg opFPR = operand.fpr(); + if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) { + // FIXME: We need a way of profiling these, and we need to hoist them into + // SpeculateDoubleOperand. + speculationCheck( + BadType, JSValueRegs(), NoNode, + m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR)); + } + + m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx)); + break; + } + case ALL_INT32_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: { + JSValueOperand operand(this, use); + GPRReg opGPR = operand.gpr(); + if (hasInt32(node.indexingType()) && !isInt32Speculation(m_state.forNode(use).m_type)) { + speculationCheck( + BadType, JSValueRegs(opGPR), use.index(), + m_jit.branch64(MacroAssembler::Below, opGPR, GPRInfo::tagTypeNumberRegister)); + } + m_jit.store64(opGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx)); + break; + } + default: + CRASH(); + break; + } } // Yuck, we should *really* have a way of also returning the storageGPR. But @@ -3376,7 +3550,7 @@ void SpeculativeJIT::compile(Node& node) if (!node.numChildren()) { flushRegisters(); GPRResult result(this); - callOperation(operationNewEmptyArray, result.gpr(), globalObject->arrayStructure()); + callOperation(operationNewEmptyArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())); cellResult(result.gpr(), m_compileIndex); break; } @@ -3386,11 +3560,65 @@ void SpeculativeJIT::compile(Node& node) EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0; for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) { - JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]); - GPRReg opGPR = operand.gpr(); - operand.use(); - - m_jit.store64(opGPR, buffer + operandIdx); + // Need to perform the speculations that this node promises to perform. If we're + // emitting code here and the indexing type is not array storage then there is + // probably something hilarious going on and we're already failing at all the + // things, but at least we're going to be sound. + Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]; + switch (node.indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: + CRASH(); + break; + case ALL_DOUBLE_INDEXING_TYPES: { + SpeculateDoubleOperand operand(this, use); + GPRTemporary scratch(this); + FPRReg opFPR = operand.fpr(); + GPRReg scratchGPR = scratch.gpr(); + if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) { + // FIXME: We need a way of profiling these, and we need to hoist them into + // SpeculateDoubleOperand. + speculationCheck( + BadType, JSValueRegs(), NoNode, + m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR)); + } + + m_jit.boxDouble(opFPR, scratchGPR); + m_jit.store64(scratchGPR, buffer + operandIdx); + break; + } + case ALL_INT32_INDEXING_TYPES: { + JSValueOperand operand(this, use); + GPRReg opGPR = operand.gpr(); + if (hasInt32(node.indexingType()) && !isInt32Speculation(m_state.forNode(use).m_type)) { + speculationCheck( + BadType, JSValueRegs(opGPR), use.index(), + m_jit.branch64(MacroAssembler::Below, opGPR, GPRInfo::tagTypeNumberRegister)); + } + m_jit.store64(opGPR, buffer + operandIdx); + break; + } + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { + JSValueOperand operand(this, use); + GPRReg opGPR = operand.gpr(); + m_jit.store64(opGPR, buffer + operandIdx); + operand.use(); + break; + } + default: + CRASH(); + break; + } + } + + switch (node.indexingType()) { + case ALL_DOUBLE_INDEXING_TYPES: + case ALL_INT32_INDEXING_TYPES: + useChildren(node); + break; + default: + break; } flushRegisters(); @@ -3406,7 +3634,7 @@ void SpeculativeJIT::compile(Node& node) GPRResult result(this); callOperation( - operationNewArray, result.gpr(), globalObject->arrayStructure(), + operationNewArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), static_cast<void*>(buffer), node.numChildren()); if (scratchSize) { @@ -3422,18 +3650,26 @@ void SpeculativeJIT::compile(Node& node) case NewArrayWithSize: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - if (!globalObject->isHavingABadTime()) { + if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) { globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); SpeculateStrictInt32Operand size(this, node.child1()); GPRTemporary result(this); GPRTemporary storage(this); GPRTemporary scratch(this); + GPRTemporary scratch2; GPRReg sizeGPR = size.gpr(); GPRReg resultGPR = result.gpr(); GPRReg storageGPR = storage.gpr(); GPRReg scratchGPR = scratch.gpr(); + GPRReg scratch2GPR = InvalidGPRReg; + + if (hasDouble(node.indexingType())) { + GPRTemporary realScratch2(this, size); + scratch2.adopt(realScratch2); + scratch2GPR = scratch2.gpr(); + } MacroAssembler::JumpList slowCases; slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX))); @@ -3446,17 +3682,28 @@ void SpeculativeJIT::compile(Node& node) emitAllocateBasicStorage(resultGPR, storageGPR)); m_jit.subPtr(scratchGPR, storageGPR); emitAllocateBasicJSObject<JSArray, MarkedBlock::None>( - TrustedImmPtr(globalObject->arrayStructure()), resultGPR, scratchGPR, + TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), resultGPR, scratchGPR, storageGPR, sizeof(JSArray), slowCases); m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength())); + if (hasDouble(node.indexingType())) { + m_jit.move(TrustedImm64(bitwise_cast<int64_t>(QNaN)), scratchGPR); + m_jit.move(sizeGPR, scratch2GPR); + MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratch2GPR); + MacroAssembler::Label loop = m_jit.label(); + m_jit.sub32(TrustedImm32(1), scratch2GPR); + m_jit.store64(scratchGPR, MacroAssembler::BaseIndex(storageGPR, scratch2GPR, MacroAssembler::TimesEight)); + m_jit.branchTest32(MacroAssembler::NonZero, scratch2GPR).linkTo(loop, &m_jit); + done.link(&m_jit); + } + addSlowPathGenerator(adoptPtr( new CallArrayAllocatorWithVariableSizeSlowPathGenerator( slowCases, this, operationNewArrayWithSize, resultGPR, - globalObject->arrayStructure(), - globalObject->arrayStructureWithArrayStorage(), + globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), + globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage), sizeGPR))); cellResult(resultGPR, m_compileIndex); @@ -3470,10 +3717,10 @@ void SpeculativeJIT::compile(Node& node) GPRReg resultGPR = result.gpr(); GPRReg structureGPR = selectScratchGPR(sizeGPR); MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)); - m_jit.move(TrustedImmPtr(globalObject->arrayStructure()), structureGPR); + m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), structureGPR); MacroAssembler::Jump done = m_jit.jump(); bigLength.link(&m_jit); - m_jit.move(TrustedImmPtr(globalObject->arrayStructureWithArrayStorage()), structureGPR); + m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)), structureGPR); done.link(&m_jit); callOperation(operationNewArrayWithSize, resultGPR, structureGPR, sizeGPR); cellResult(resultGPR, m_compileIndex); @@ -3520,7 +3767,8 @@ void SpeculativeJIT::compile(Node& node) case NewArrayBuffer: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - if (!globalObject->isHavingABadTime()) { + IndexingType indexingType = node.indexingType(); + if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) { globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); unsigned numElements = node.numConstants(); @@ -3531,13 +3779,23 @@ void SpeculativeJIT::compile(Node& node) GPRReg resultGPR = result.gpr(); GPRReg storageGPR = storage.gpr(); - emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements); + emitAllocateJSArray(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), resultGPR, storageGPR, numElements); + ASSERT(indexingType & IsArray); JSValue* data = m_jit.codeBlock()->constantBuffer(node.startConstant()); - for (unsigned index = 0; index < node.numConstants(); ++index) { - m_jit.store64( - Imm64(JSValue::encode(data[index])), - MacroAssembler::Address(storageGPR, sizeof(JSValue) * index)); + if (indexingType == ArrayWithDouble) { + for (unsigned index = 0; index < node.numConstants(); ++index) { + double value = data[index].asNumber(); + m_jit.store64( + Imm64(bitwise_cast<int64_t>(value)), + MacroAssembler::Address(storageGPR, sizeof(double) * index)); + } + } else { + for (unsigned index = 0; index < node.numConstants(); ++index) { + m_jit.store64( + Imm64(JSValue::encode(data[index])), + MacroAssembler::Address(storageGPR, sizeof(JSValue) * index)); + } } cellResult(resultGPR, m_compileIndex); @@ -3547,7 +3805,7 @@ void SpeculativeJIT::compile(Node& node) flushRegisters(); GPRResult result(this); - callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructure(), node.startConstant(), node.numConstants()); + callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), node.startConstant(), node.numConstants()); cellResult(result.gpr(), m_compileIndex); break; diff --git a/Source/JavaScriptCore/heap/BlockAllocator.cpp b/Source/JavaScriptCore/heap/BlockAllocator.cpp index 16f607396..daba93805 100644 --- a/Source/JavaScriptCore/heap/BlockAllocator.cpp +++ b/Source/JavaScriptCore/heap/BlockAllocator.cpp @@ -28,6 +28,7 @@ #include "CopiedBlock.h" #include "MarkedBlock.h" +#include "WeakBlock.h" #include <wtf/CurrentTime.h> namespace JSC { @@ -35,6 +36,7 @@ namespace JSC { BlockAllocator::BlockAllocator() : m_copiedRegionSet(CopiedBlock::blockSize) , m_markedRegionSet(MarkedBlock::blockSize) + , m_weakRegionSet(WeakBlock::blockSize) , m_numberOfEmptyRegions(0) , m_isCurrentlyAllocating(false) , m_blockFreeingThreadShouldQuit(false) diff --git a/Source/JavaScriptCore/heap/BlockAllocator.h b/Source/JavaScriptCore/heap/BlockAllocator.h index a41df1aab..f8ce39530 100644 --- a/Source/JavaScriptCore/heap/BlockAllocator.h +++ b/Source/JavaScriptCore/heap/BlockAllocator.h @@ -39,6 +39,7 @@ class BlockAllocator; class CopiedBlock; class MarkedBlock; class Region; +class WeakBlock; // Simple allocator to reduce VM cost by holding onto blocks of memory for // short periods of time and then freeing them on a secondary thread. @@ -184,6 +185,7 @@ private: RegionSet m_copiedRegionSet; RegionSet m_markedRegionSet; + RegionSet m_weakRegionSet; DoublyLinkedList<Region> m_emptyRegions; size_t m_numberOfEmptyRegions; @@ -311,6 +313,12 @@ inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<MarkedBlock>() } template <> +inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<WeakBlock>() +{ + return m_weakRegionSet; +} + +template <> inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<CopiedBlock> >() { return m_copiedRegionSet; @@ -322,6 +330,12 @@ inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<MarkedB return m_markedRegionSet; } +template <> +inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<WeakBlock> >() +{ + return m_weakRegionSet; +} + template <typename T> inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor() { diff --git a/Source/JavaScriptCore/heap/ConservativeRoots.cpp b/Source/JavaScriptCore/heap/ConservativeRoots.cpp index 7fe22dfff..752ce2775 100644 --- a/Source/JavaScriptCore/heap/ConservativeRoots.cpp +++ b/Source/JavaScriptCore/heap/ConservativeRoots.cpp @@ -26,9 +26,9 @@ #include "config.h" #include "ConservativeRoots.h" -#include "CopiedSpace.h" -#include "CopiedSpaceInlineMethods.h" #include "CodeBlock.h" +#include "CopiedSpace.h" +#include "CopiedSpaceInlines.h" #include "DFGCodeBlocks.h" #include "JSCell.h" #include "JSObject.h" diff --git a/Source/JavaScriptCore/heap/CopiedBlock.h b/Source/JavaScriptCore/heap/CopiedBlock.h index af36f55df..83fdb08da 100644 --- a/Source/JavaScriptCore/heap/CopiedBlock.h +++ b/Source/JavaScriptCore/heap/CopiedBlock.h @@ -29,7 +29,7 @@ #include "BlockAllocator.h" #include "HeapBlock.h" #include "JSValue.h" -#include "JSValueInlineMethods.h" +#include "JSValueInlines.h" #include "Options.h" #include <wtf/Atomics.h> diff --git a/Source/JavaScriptCore/heap/CopiedSpace.cpp b/Source/JavaScriptCore/heap/CopiedSpace.cpp index c228f9460..e4141c1d7 100644 --- a/Source/JavaScriptCore/heap/CopiedSpace.cpp +++ b/Source/JavaScriptCore/heap/CopiedSpace.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "CopiedSpace.h" -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "GCActivityCallback.h" #include "Options.h" diff --git a/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h b/Source/JavaScriptCore/heap/CopiedSpaceInlines.h index c244015e7..9d222f549 100644 --- a/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h +++ b/Source/JavaScriptCore/heap/CopiedSpaceInlines.h @@ -23,8 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CopiedSpaceInlineMethods_h -#define CopiedSpaceInlineMethods_h +#ifndef CopiedSpaceInlines_h +#define CopiedSpaceInlines_h #include "CopiedBlock.h" #include "CopiedSpace.h" @@ -182,4 +182,5 @@ inline CopiedBlock* CopiedSpace::blockFor(void* ptr) } // namespace JSC -#endif +#endif // CopiedSpaceInlines_h + diff --git a/Source/JavaScriptCore/heap/CopyVisitor.cpp b/Source/JavaScriptCore/heap/CopyVisitor.cpp index ae826f0d2..22ab57882 100644 --- a/Source/JavaScriptCore/heap/CopyVisitor.cpp +++ b/Source/JavaScriptCore/heap/CopyVisitor.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "CopyVisitor.h" -#include "CopyVisitorInlineMethods.h" +#include "CopyVisitorInlines.h" #include "GCThreadSharedData.h" #include "JSCell.h" #include "JSObject.h" diff --git a/Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h b/Source/JavaScriptCore/heap/CopyVisitorInlines.h index eb7bd2e82..bd7879429 100644 --- a/Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h +++ b/Source/JavaScriptCore/heap/CopyVisitorInlines.h @@ -23,8 +23,8 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CopyVisitorInlineMethods_h -#define CopyVisitorInlineMethods_h +#ifndef CopyVisitorInlines_h +#define CopyVisitorInlines_h #include "ClassInfo.h" #include "CopyVisitor.h" @@ -116,4 +116,5 @@ inline void CopyVisitor::didCopy(void* ptr, size_t bytes) } // namespace JSC -#endif +#endif // CopyVisitorInlines_h + diff --git a/Source/JavaScriptCore/heap/GCThread.cpp b/Source/JavaScriptCore/heap/GCThread.cpp index ce3bbedc9..7caa7d588 100644 --- a/Source/JavaScriptCore/heap/GCThread.cpp +++ b/Source/JavaScriptCore/heap/GCThread.cpp @@ -27,7 +27,7 @@ #include "GCThread.h" #include "CopyVisitor.h" -#include "CopyVisitorInlineMethods.h" +#include "CopyVisitorInlines.h" #include "GCThreadSharedData.h" #include "SlotVisitor.h" #include <wtf/MainThread.h> diff --git a/Source/JavaScriptCore/heap/GCThreadSharedData.cpp b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp index 446b41c2f..cf12d4bcd 100644 --- a/Source/JavaScriptCore/heap/GCThreadSharedData.cpp +++ b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp @@ -27,12 +27,12 @@ #include "GCThreadSharedData.h" #include "CopyVisitor.h" -#include "CopyVisitorInlineMethods.h" +#include "CopyVisitorInlines.h" #include "GCThread.h" #include "JSGlobalData.h" #include "MarkStack.h" #include "SlotVisitor.h" -#include "SlotVisitorInlineMethods.h" +#include "SlotVisitorInlines.h" namespace JSC { diff --git a/Source/JavaScriptCore/heap/HandleStack.cpp b/Source/JavaScriptCore/heap/HandleStack.cpp index 42eb326a5..a5653c748 100644 --- a/Source/JavaScriptCore/heap/HandleStack.cpp +++ b/Source/JavaScriptCore/heap/HandleStack.cpp @@ -27,8 +27,8 @@ #include "HandleStack.h" #include "HeapRootVisitor.h" -#include "JSValueInlineMethods.h" #include "JSObject.h" +#include "JSValueInlines.h" namespace JSC { diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp index c455fc2b1..0fb65e205 100644 --- a/Source/JavaScriptCore/heap/Heap.cpp +++ b/Source/JavaScriptCore/heap/Heap.cpp @@ -24,8 +24,8 @@ #include "CodeBlock.h" #include "ConservativeRoots.h" #include "CopiedSpace.h" -#include "CopiedSpaceInlineMethods.h" -#include "CopyVisitorInlineMethods.h" +#include "CopiedSpaceInlines.h" +#include "CopyVisitorInlines.h" #include "GCActivityCallback.h" #include "HeapRootVisitor.h" #include "HeapStatistics.h" diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h index 51cebdc0e..d0d03959b 100644 --- a/Source/JavaScriptCore/heap/Heap.h +++ b/Source/JavaScriptCore/heap/Heap.h @@ -188,6 +188,7 @@ namespace JSC { friend class SlotVisitor; friend class IncrementalSweeper; friend class HeapStatistics; + friend class WeakSet; template<typename T> friend void* allocateCell(Heap&); template<typename T> friend void* allocateCell(Heap&, size_t); diff --git a/Source/JavaScriptCore/heap/HeapRootVisitor.h b/Source/JavaScriptCore/heap/HeapRootVisitor.h index 9849d7c39..5b11a5ead 100644 --- a/Source/JavaScriptCore/heap/HeapRootVisitor.h +++ b/Source/JavaScriptCore/heap/HeapRootVisitor.h @@ -27,7 +27,7 @@ #define HeapRootVisitor_h #include "SlotVisitor.h" -#include "SlotVisitorInlineMethods.h" +#include "SlotVisitorInlines.h" namespace JSC { diff --git a/Source/JavaScriptCore/heap/HeapStatistics.cpp b/Source/JavaScriptCore/heap/HeapStatistics.cpp index 8340bfa37..387621558 100644 --- a/Source/JavaScriptCore/heap/HeapStatistics.cpp +++ b/Source/JavaScriptCore/heap/HeapStatistics.cpp @@ -41,8 +41,8 @@ namespace JSC { double HeapStatistics::s_startTime = 0.0; double HeapStatistics::s_endTime = 0.0; -Deque<double>* HeapStatistics::s_pauseTimeStarts = 0; -Deque<double>* HeapStatistics::s_pauseTimeEnds = 0; +Vector<double>* HeapStatistics::s_pauseTimeStarts = 0; +Vector<double>* HeapStatistics::s_pauseTimeEnds = 0; #if OS(UNIX) @@ -50,8 +50,8 @@ void HeapStatistics::initialize() { ASSERT(Options::recordGCPauseTimes()); s_startTime = WTF::monotonicallyIncreasingTime(); - s_pauseTimeStarts = new Deque<double>(); - s_pauseTimeEnds = new Deque<double>(); + s_pauseTimeStarts = new Vector<double>(); + s_pauseTimeEnds = new Vector<double>(); } void HeapStatistics::recordGCPauseTime(double start, double end) @@ -82,8 +82,8 @@ void HeapStatistics::logStatistics() if (Options::recordGCPauseTimes()) { dataLog(", \"pause_times\": ["); - Deque<double>::iterator startIt = s_pauseTimeStarts->begin(); - Deque<double>::iterator endIt = s_pauseTimeEnds->begin(); + Vector<double>::iterator startIt = s_pauseTimeStarts->begin(); + Vector<double>::iterator endIt = s_pauseTimeEnds->begin(); if (startIt != s_pauseTimeStarts->end() && endIt != s_pauseTimeEnds->end()) { dataLog("[%f, %f]", *startIt, *endIt); ++startIt; diff --git a/Source/JavaScriptCore/heap/HeapStatistics.h b/Source/JavaScriptCore/heap/HeapStatistics.h index 0800f0c16..ce7a40a79 100644 --- a/Source/JavaScriptCore/heap/HeapStatistics.h +++ b/Source/JavaScriptCore/heap/HeapStatistics.h @@ -49,8 +49,8 @@ public: private: static void logStatistics(); - static Deque<double>* s_pauseTimeStarts; - static Deque<double>* s_pauseTimeEnds; + static Vector<double>* s_pauseTimeStarts; + static Vector<double>* s_pauseTimeEnds; static double s_startTime; static double s_endTime; }; diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp index 582439fd2..aa8785e9c 100644 --- a/Source/JavaScriptCore/heap/MarkStack.cpp +++ b/Source/JavaScriptCore/heap/MarkStack.cpp @@ -25,18 +25,18 @@ #include "config.h" #include "MarkStack.h" -#include "MarkStackInlineMethods.h" +#include "MarkStackInlines.h" -#include "CopiedSpace.h" -#include "CopiedSpaceInlineMethods.h" #include "ConservativeRoots.h" +#include "CopiedSpace.h" +#include "CopiedSpaceInlines.h" #include "Heap.h" #include "Options.h" #include "JSArray.h" #include "JSCell.h" #include "JSObject.h" -#include "SlotVisitorInlineMethods.h" +#include "SlotVisitorInlines.h" #include "Structure.h" #include "WriteBarrier.h" #include <wtf/Atomics.h> diff --git a/Source/JavaScriptCore/heap/MarkStackInlineMethods.h b/Source/JavaScriptCore/heap/MarkStackInlines.h index d3276d7fa..841ac06b8 100644 --- a/Source/JavaScriptCore/heap/MarkStackInlineMethods.h +++ b/Source/JavaScriptCore/heap/MarkStackInlines.h @@ -23,8 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MarkStackInlineMethods_h -#define MarkStackInlineMethods_h +#ifndef MarkStackInlines_h +#define MarkStackInlines_h #include "GCThreadSharedData.h" #include "MarkStack.h" @@ -37,14 +37,14 @@ inline size_t MarkStackArray::postIncTop() ASSERT(result == m_topSegment->m_top++); return result; } - + inline size_t MarkStackArray::preDecTop() { size_t result = --m_top; ASSERT(result == --m_topSegment->m_top); return result; } - + inline void MarkStackArray::setTopForFullSegment() { ASSERT(m_topSegment->m_top == m_segmentCapacity); @@ -110,4 +110,5 @@ inline size_t MarkStackArray::size() } // namespace JSC -#endif +#endif // MarkStackInlines_h + diff --git a/Source/JavaScriptCore/heap/SlotVisitor.cpp b/Source/JavaScriptCore/heap/SlotVisitor.cpp index 3919705d0..8b4d7397e 100644 --- a/Source/JavaScriptCore/heap/SlotVisitor.cpp +++ b/Source/JavaScriptCore/heap/SlotVisitor.cpp @@ -3,7 +3,7 @@ #include "ConservativeRoots.h" #include "CopiedSpace.h" -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "GCThread.h" #include "JSArray.h" #include "JSDestructibleObject.h" diff --git a/Source/JavaScriptCore/heap/SlotVisitor.h b/Source/JavaScriptCore/heap/SlotVisitor.h index dcd4b75ef..34b1bc80b 100644 --- a/Source/JavaScriptCore/heap/SlotVisitor.h +++ b/Source/JavaScriptCore/heap/SlotVisitor.h @@ -27,7 +27,7 @@ #define SlotVisitor_h #include "HandleTypes.h" -#include "MarkStackInlineMethods.h" +#include "MarkStackInlines.h" #include <wtf/text/StringHash.h> diff --git a/Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h b/Source/JavaScriptCore/heap/SlotVisitorInlines.h index e5908bf36..b0f30b6ca 100644 --- a/Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h +++ b/Source/JavaScriptCore/heap/SlotVisitorInlines.h @@ -23,10 +23,10 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SlotVisitorInlineMethods_h -#define SlotVisitorInlineMethods_h +#ifndef SlotVisitorInlines_h +#define SlotVisitorInlines_h -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "Options.h" #include "SlotVisitor.h" @@ -170,5 +170,5 @@ inline void SlotVisitor::copyLater(void* ptr, size_t bytes) } // namespace JSC -#endif // SlotVisitorInlineMethods_h +#endif // SlotVisitorInlines_h diff --git a/Source/JavaScriptCore/heap/WeakBlock.cpp b/Source/JavaScriptCore/heap/WeakBlock.cpp index 99e306b85..5f01f34b3 100644 --- a/Source/JavaScriptCore/heap/WeakBlock.cpp +++ b/Source/JavaScriptCore/heap/WeakBlock.cpp @@ -34,18 +34,14 @@ namespace JSC { -WeakBlock* WeakBlock::create() +WeakBlock* WeakBlock::create(DeadBlock* block) { - void* allocation = fastMalloc(blockSize); - return new (NotNull, allocation) WeakBlock; + Region* region = block->region(); + return new (NotNull, block) WeakBlock(region); } -void WeakBlock::destroy(WeakBlock* block) -{ - fastFree(block); -} - -WeakBlock::WeakBlock() +WeakBlock::WeakBlock(Region* region) + : HeapBlock<WeakBlock>(region) { for (size_t i = 0; i < weakImplCount(); ++i) { WeakImpl* weakImpl = &weakImpls()[i]; diff --git a/Source/JavaScriptCore/heap/WeakBlock.h b/Source/JavaScriptCore/heap/WeakBlock.h index 6461f7b2f..fd28101fd 100644 --- a/Source/JavaScriptCore/heap/WeakBlock.h +++ b/Source/JavaScriptCore/heap/WeakBlock.h @@ -34,14 +34,15 @@ namespace JSC { +class DeadBlock; class HeapRootVisitor; class JSValue; class WeakHandleOwner; -class WeakBlock : public DoublyLinkedListNode<WeakBlock> { +class WeakBlock : public HeapBlock<WeakBlock> { public: friend class WTF::DoublyLinkedListNode<WeakBlock>; - static const size_t blockSize = 3 * KB; // 5% of MarkedBlock size + static const size_t blockSize = 4 * KB; // 5% of MarkedBlock size struct FreeCell { FreeCell* next; @@ -55,8 +56,7 @@ public: FreeCell* freeList; }; - static WeakBlock* create(); - static void destroy(WeakBlock*); + static WeakBlock* create(DeadBlock*); static WeakImpl* asWeakImpl(FreeCell*); @@ -73,15 +73,13 @@ public: private: static FreeCell* asFreeCell(WeakImpl*); - WeakBlock(); + WeakBlock(Region*); WeakImpl* firstWeakImpl(); void finalize(WeakImpl*); WeakImpl* weakImpls(); size_t weakImplCount(); void addToFreeList(FreeCell**, WeakImpl*); - WeakBlock* m_prev; - WeakBlock* m_next; SweepResult m_sweepResult; }; diff --git a/Source/JavaScriptCore/heap/WeakSet.cpp b/Source/JavaScriptCore/heap/WeakSet.cpp index 2804968f8..67b1d0613 100644 --- a/Source/JavaScriptCore/heap/WeakSet.cpp +++ b/Source/JavaScriptCore/heap/WeakSet.cpp @@ -36,7 +36,7 @@ WeakSet::~WeakSet() WeakBlock* next = 0; for (WeakBlock* block = m_blocks.head(); block; block = next) { next = block->next(); - WeakBlock::destroy(block); + heap()->blockAllocator().deallocate(WeakBlock::destroy(block)); } m_blocks.clear(); } @@ -73,7 +73,7 @@ WeakBlock::FreeCell* WeakSet::tryFindAllocator() WeakBlock::FreeCell* WeakSet::addAllocator() { - WeakBlock* block = WeakBlock::create(); + WeakBlock* block = WeakBlock::create(heap()->blockAllocator().allocate<WeakBlock>()); heap()->didAllocate(WeakBlock::blockSize); m_blocks.append(block); WeakBlock::SweepResult sweepResult = block->takeSweepResult(); diff --git a/Source/JavaScriptCore/jit/HostCallReturnValue.cpp b/Source/JavaScriptCore/jit/HostCallReturnValue.cpp index c4d2e6ad9..967c499b9 100644 --- a/Source/JavaScriptCore/jit/HostCallReturnValue.cpp +++ b/Source/JavaScriptCore/jit/HostCallReturnValue.cpp @@ -29,7 +29,7 @@ #include "CallFrame.h" #include <wtf/InlineASM.h> #include "JSObject.h" -#include "JSValueInlineMethods.h" +#include "JSValueInlines.h" namespace JSC { diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp index 3102c7693..ffd18b571 100644 --- a/Source/JavaScriptCore/jit/JIT.cpp +++ b/Source/JavaScriptCore/jit/JIT.cpp @@ -38,7 +38,7 @@ JSC::MacroAssemblerX86Common::SSE2CheckState JSC::MacroAssemblerX86Common::s_sse #include <wtf/CryptographicallyRandomNumber.h> #include "DFGNode.h" // for DFG_SUCCESS_STATS #include "Interpreter.h" -#include "JITInlineMethods.h" +#include "JITInlines.h" #include "JITStubCall.h" #include "JSArray.h" #include "JSFunction.h" diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h index dcf87d352..9b0879fe2 100644 --- a/Source/JavaScriptCore/jit/JIT.h +++ b/Source/JavaScriptCore/jit/JIT.h @@ -474,7 +474,9 @@ namespace JSC { // Property is int-checked and zero extended. Base is cell checked. // Structure is already profiled. Returns the slow cases. Fall-through // case contains result in regT0, and it is not yet profiled. - JumpList emitContiguousGetByVal(Instruction*, PatchableJump& badType); + JumpList emitInt32GetByVal(Instruction* instruction, PatchableJump& badType) { return emitContiguousGetByVal(instruction, badType, Int32Shape); } + JumpList emitDoubleGetByVal(Instruction*, PatchableJump& badType); + JumpList emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape = ContiguousShape); JumpList emitArrayStorageGetByVal(Instruction*, PatchableJump& badType); JumpList emitIntTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize, TypedArraySignedness); JumpList emitFloatTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize); @@ -483,7 +485,20 @@ namespace JSC { // The value to store is not yet loaded. Property is int-checked and // zero-extended. Base is cell checked. Structure is already profiled. // returns the slow cases. - JumpList emitContiguousPutByVal(Instruction*, PatchableJump& badType); + JumpList emitInt32PutByVal(Instruction* currentInstruction, PatchableJump& badType) + { + return emitGenericContiguousPutByVal<Int32Shape>(currentInstruction, badType); + } + JumpList emitDoublePutByVal(Instruction* currentInstruction, PatchableJump& badType) + { + return emitGenericContiguousPutByVal<DoubleShape>(currentInstruction, badType); + } + JumpList emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) + { + return emitGenericContiguousPutByVal<ContiguousShape>(currentInstruction, badType); + } + template<IndexingType indexingShape> + JumpList emitGenericContiguousPutByVal(Instruction*, PatchableJump& badType); JumpList emitArrayStoragePutByVal(Instruction*, PatchableJump& badType); JumpList emitIntTypedArrayPutByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize, TypedArraySignedness, TypedArrayRounding); JumpList emitFloatTypedArrayPutByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize); diff --git a/Source/JavaScriptCore/jit/JITArithmetic.cpp b/Source/JavaScriptCore/jit/JITArithmetic.cpp index 21d59bc33..bcb3dd74a 100644 --- a/Source/JavaScriptCore/jit/JITArithmetic.cpp +++ b/Source/JavaScriptCore/jit/JITArithmetic.cpp @@ -29,7 +29,7 @@ #include "JIT.h" #include "CodeBlock.h" -#include "JITInlineMethods.h" +#include "JITInlines.h" #include "JITStubCall.h" #include "JITStubs.h" #include "JSArray.h" @@ -1090,18 +1090,20 @@ void JIT::emit_op_div(Instruction* currentInstruction) // access). So if we are DFG compiling anything in the program, we want this code to // ensure that it produces integers whenever possible. - // FIXME: This will fail to convert to integer if the result is zero. We should - // distinguish between positive zero and negative zero here. - JumpList notInteger; branchConvertDoubleToInt32(fpRegT0, regT0, notInteger, fpRegT1); // If we've got an integer, we might as well make that the result of the division. emitFastArithReTagImmediate(regT0, regT0); Jump isInteger = jump(); notInteger.link(this); - add32(TrustedImm32(1), AbsoluteAddress(&m_codeBlock->addSpecialFastCaseProfile(m_bytecodeOffset)->m_counter)); moveDoubleTo64(fpRegT0, regT0); + Jump doubleZero = branchTest64(Zero, regT0); + add32(TrustedImm32(1), AbsoluteAddress(&m_codeBlock->addSpecialFastCaseProfile(m_bytecodeOffset)->m_counter)); sub64(tagTypeNumberRegister, regT0); + Jump trueDouble = jump(); + doubleZero.link(this); + move(tagTypeNumberRegister, regT0); + trueDouble.link(this); isInteger.link(this); #else // Double result. diff --git a/Source/JavaScriptCore/jit/JITArithmetic32_64.cpp b/Source/JavaScriptCore/jit/JITArithmetic32_64.cpp index 62a359eeb..960d06091 100644 --- a/Source/JavaScriptCore/jit/JITArithmetic32_64.cpp +++ b/Source/JavaScriptCore/jit/JITArithmetic32_64.cpp @@ -30,7 +30,7 @@ #include "JIT.h" #include "CodeBlock.h" -#include "JITInlineMethods.h" +#include "JITInlines.h" #include "JITStubCall.h" #include "JITStubs.h" #include "JSArray.h" diff --git a/Source/JavaScriptCore/jit/JITCall.cpp b/Source/JavaScriptCore/jit/JITCall.cpp index 074bf7f97..006c5b741 100644 --- a/Source/JavaScriptCore/jit/JITCall.cpp +++ b/Source/JavaScriptCore/jit/JITCall.cpp @@ -31,7 +31,7 @@ #include "Arguments.h" #include "CodeBlock.h" -#include "JITInlineMethods.h" +#include "JITInlines.h" #include "JITStubCall.h" #include "JSArray.h" #include "JSFunction.h" diff --git a/Source/JavaScriptCore/jit/JITCall32_64.cpp b/Source/JavaScriptCore/jit/JITCall32_64.cpp index ad827cdf9..ecd5cf126 100644 --- a/Source/JavaScriptCore/jit/JITCall32_64.cpp +++ b/Source/JavaScriptCore/jit/JITCall32_64.cpp @@ -32,7 +32,7 @@ #include "Arguments.h" #include "CodeBlock.h" #include "Interpreter.h" -#include "JITInlineMethods.h" +#include "JITInlines.h" #include "JITStubCall.h" #include "JSArray.h" #include "JSFunction.h" diff --git a/Source/JavaScriptCore/jit/JITExceptions.cpp b/Source/JavaScriptCore/jit/JITExceptions.cpp index f6cec24bd..aeb869474 100644 --- a/Source/JavaScriptCore/jit/JITExceptions.cpp +++ b/Source/JavaScriptCore/jit/JITExceptions.cpp @@ -39,7 +39,7 @@ namespace JSC { ExceptionHandler genericThrow(JSGlobalData* globalData, ExecState* callFrame, JSValue exceptionValue, unsigned vPCIndex) { ASSERT(exceptionValue); - + globalData->exception = JSValue(); HandlerInfo* handler = globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex); // This may update callFrame & exceptionValue! globalData->exception = exceptionValue; diff --git a/Source/JavaScriptCore/jit/JITInlineMethods.h b/Source/JavaScriptCore/jit/JITInlines.h index 410bdf710..e6f95b94c 100644 --- a/Source/JavaScriptCore/jit/JITInlineMethods.h +++ b/Source/JavaScriptCore/jit/JITInlines.h @@ -23,8 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JITInlineMethods_h -#define JITInlineMethods_h +#ifndef JITInlines_h +#define JITInlines_h #if ENABLE(JIT) @@ -528,12 +528,12 @@ inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfi #endif } -static inline bool arrayProfileSaw(ArrayProfile* profile, IndexingType capability) +static inline bool arrayProfileSaw(ArrayModes arrayModes, IndexingType capability) { #if ENABLE(VALUE_PROFILER) - return !!(profile->observedArrayModes() & (asArrayModes(NonArray | capability) | asArrayModes(ArrayClass | capability))); + return arrayModesInclude(arrayModes, capability); #else - UNUSED_PARAM(profile); + UNUSED_PARAM(arrayModes); UNUSED_PARAM(capability); return false; #endif @@ -541,9 +541,20 @@ static inline bool arrayProfileSaw(ArrayProfile* profile, IndexingType capabilit inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile) { - if (arrayProfileSaw(profile, ArrayStorageShape)) +#if ENABLE(VALUE_PROFILER) + profile->computeUpdatedPrediction(m_codeBlock); + ArrayModes arrayModes = profile->observedArrayModes(); + if (arrayProfileSaw(arrayModes, DoubleShape)) + return JITDouble; + if (arrayProfileSaw(arrayModes, Int32Shape)) + return JITInt32; + if (arrayProfileSaw(arrayModes, ArrayStorageShape)) return JITArrayStorage; return JITContiguous; +#else + UNUSED_PARAM(profile); + return JITContiguous; +#endif } #if USE(JSVALUE32_64) @@ -998,4 +1009,5 @@ ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg) #endif // ENABLE(JIT) -#endif +#endif // JITInlines_h + diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp index 249dcbac9..3053918b8 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp @@ -29,9 +29,9 @@ #include "JIT.h" #include "Arguments.h" -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "Heap.h" -#include "JITInlineMethods.h" +#include "JITInlines.h" #include "JITStubCall.h" #include "JSArray.h" #include "JSCell.h" @@ -1625,7 +1625,7 @@ void JIT::emit_resolve_operations(ResolveOperations* resolveOperations, const in break; case ResolveOperation::ReturnScopeAsBase: emitStoreCell(*baseVR, scope); - ASSERT(!value); + ASSERT(value == regT0); move(scope, value); #if USE(JSVALUE32_64) move(TrustedImm32(JSValue::CellTag), valueTag); @@ -1952,6 +1952,7 @@ void JIT::emit_op_new_array(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_new_array); stubCall.addArgument(TrustedImm32(currentInstruction[2].u.operand)); stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand)); + stubCall.addArgument(TrustedImmPtr(currentInstruction[4].u.arrayAllocationProfile)); stubCall.call(currentInstruction[1].u.operand); } @@ -1963,6 +1964,7 @@ void JIT::emit_op_new_array_with_size(Instruction* currentInstruction) #else stubCall.addArgument(currentInstruction[2].u.operand); #endif + stubCall.addArgument(TrustedImmPtr(currentInstruction[3].u.arrayAllocationProfile)); stubCall.call(currentInstruction[1].u.operand); } @@ -1971,6 +1973,7 @@ void JIT::emit_op_new_array_buffer(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_new_array_buffer); stubCall.addArgument(TrustedImm32(currentInstruction[2].u.operand)); stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand)); + stubCall.addArgument(TrustedImmPtr(currentInstruction[4].u.arrayAllocationProfile)); stubCall.call(currentInstruction[1].u.operand); } diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp index 9c5d260ab..23361c099 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -30,7 +30,7 @@ #if USE(JSVALUE32_64) #include "JIT.h" -#include "JITInlineMethods.h" +#include "JITInlines.h" #include "JITStubCall.h" #include "JSArray.h" #include "JSCell.h" diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp index 6362598f4..3110be38c 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp @@ -32,7 +32,7 @@ #include "GCAwareJITStubRoutine.h" #include "GetterSetter.h" #include "Interpreter.h" -#include "JITInlineMethods.h" +#include "JITInlines.h" #include "JITStubCall.h" #include "JSArray.h" #include "JSFunction.h" @@ -98,7 +98,7 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) unsigned base = currentInstruction[2].u.operand; unsigned property = currentInstruction[3].u.operand; ArrayProfile* profile = currentInstruction[4].u.arrayProfile; - + emitGetVirtualRegisters(base, regT0, property, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT1); @@ -120,6 +120,12 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) JITArrayMode mode = chooseArrayMode(profile); switch (mode) { + case JITInt32: + slowCases = emitInt32GetByVal(currentInstruction, badType); + break; + case JITDouble: + slowCases = emitDoubleGetByVal(currentInstruction, badType); + break; case JITContiguous: slowCases = emitContiguousGetByVal(currentInstruction, badType); break; @@ -148,11 +154,26 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done)); } -JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType) +JIT::JumpList JIT::emitDoubleGetByVal(Instruction*, PatchableJump& badType) { JumpList slowCases; - badType = patchableBranch32(NotEqual, regT2, TrustedImm32(ContiguousShape)); + badType = patchableBranch32(NotEqual, regT2, TrustedImm32(DoubleShape)); + loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2); + slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength()))); + loadDouble(BaseIndex(regT2, regT1, TimesEight), fpRegT0); + slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0)); + moveDoubleTo64(fpRegT0, regT0); + sub64(tagTypeNumberRegister, regT0); + + return slowCases; +} + +JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape) +{ + JumpList slowCases; + + badType = patchableBranch32(NotEqual, regT2, TrustedImm32(expectedShape)); loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2); slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength()))); load64(BaseIndex(regT2, regT1, TimesEight), regT0); @@ -304,6 +325,12 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) JITArrayMode mode = chooseArrayMode(profile); switch (mode) { + case JITInt32: + slowCases = emitInt32PutByVal(currentInstruction, badType); + break; + case JITDouble: + slowCases = emitDoublePutByVal(currentInstruction, badType); + break; case JITContiguous: slowCases = emitContiguousPutByVal(currentInstruction, badType); break; @@ -325,24 +352,49 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) emitWriteBarrier(regT0, regT3, regT1, regT3, ShouldFilterImmediates, WriteBarrierForPropertyAccess); } -JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) +template<IndexingType indexingShape> +JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) { unsigned value = currentInstruction[3].u.operand; ArrayProfile* profile = currentInstruction[4].u.arrayProfile; - badType = patchableBranch32(NotEqual, regT2, TrustedImm32(ContiguousShape)); + JumpList slowCases; + + badType = patchableBranch32(NotEqual, regT2, TrustedImm32(indexingShape)); loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2); Jump outOfBounds = branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength())); Label storeResult = label(); emitGetVirtualRegister(value, regT3); - store64(regT3, BaseIndex(regT2, regT1, TimesEight)); + switch (indexingShape) { + case Int32Shape: + slowCases.append(emitJumpIfNotImmediateInteger(regT3)); + store64(regT3, BaseIndex(regT2, regT1, TimesEight)); + break; + case DoubleShape: { + Jump notInt = emitJumpIfNotImmediateInteger(regT3); + convertInt32ToDouble(regT3, fpRegT0); + Jump ready = jump(); + notInt.link(this); + add64(tagTypeNumberRegister, regT3); + move64ToDouble(regT3, fpRegT0); + slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0)); + ready.link(this); + storeDouble(fpRegT0, BaseIndex(regT2, regT1, TimesEight)); + break; + } + case ContiguousShape: + store64(regT3, BaseIndex(regT2, regT1, TimesEight)); + break; + default: + CRASH(); + break; + } Jump done = jump(); outOfBounds.link(this); - JumpList slowCases; slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfVectorLength()))); emitArrayProfileStoreToHoleSpecialCase(profile); @@ -394,12 +446,23 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas unsigned base = currentInstruction[1].u.operand; unsigned property = currentInstruction[2].u.operand; unsigned value = currentInstruction[3].u.operand; + ArrayProfile* profile = currentInstruction[4].u.arrayProfile; linkSlowCase(iter); // property int32 check linkSlowCaseIfNotJSCell(iter, base); // base cell check linkSlowCase(iter); // base not array check linkSlowCase(iter); // out of bounds + JITArrayMode mode = chooseArrayMode(profile); + switch (mode) { + case JITInt32: + case JITDouble: + linkSlowCase(iter); // value type check + break; + default: + break; + } + Label slowPath = label(); JITStubCall stubPutByValCall(this, cti_op_put_by_val); @@ -1312,6 +1375,12 @@ void JIT::privateCompileGetByVal(ByValInfo* byValInfo, ReturnAddressPtr returnAd JumpList slowCases; switch (arrayMode) { + case JITInt32: + slowCases = emitInt32GetByVal(currentInstruction, badType); + break; + case JITDouble: + slowCases = emitDoubleGetByVal(currentInstruction, badType); + break; case JITContiguous: slowCases = emitContiguousGetByVal(currentInstruction, badType); break; @@ -1375,6 +1444,12 @@ void JIT::privateCompilePutByVal(ByValInfo* byValInfo, ReturnAddressPtr returnAd JumpList slowCases; switch (arrayMode) { + case JITInt32: + slowCases = emitInt32PutByVal(currentInstruction, badType); + break; + case JITDouble: + slowCases = emitDoublePutByVal(currentInstruction, badType); + break; case JITContiguous: slowCases = emitContiguousPutByVal(currentInstruction, badType); break; diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp index 939766f04..414827420 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp @@ -32,7 +32,7 @@ #include "CodeBlock.h" #include "GCAwareJITStubRoutine.h" #include "Interpreter.h" -#include "JITInlineMethods.h" +#include "JITInlines.h" #include "JITStubCall.h" #include "JSArray.h" #include "JSFunction.h" @@ -153,6 +153,12 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) JITArrayMode mode = chooseArrayMode(profile); switch (mode) { + case JITInt32: + slowCases = emitInt32GetByVal(currentInstruction, badType); + break; + case JITDouble: + slowCases = emitDoubleGetByVal(currentInstruction, badType); + break; case JITContiguous: slowCases = emitContiguousGetByVal(currentInstruction, badType); break; @@ -181,11 +187,11 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done)); } -JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType) +JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape) { JumpList slowCases; - badType = patchableBranch32(NotEqual, regT1, TrustedImm32(ContiguousShape)); + badType = patchableBranch32(NotEqual, regT1, TrustedImm32(expectedShape)); loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3); slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength()))); @@ -197,6 +203,22 @@ JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType) return slowCases; } +JIT::JumpList JIT::emitDoubleGetByVal(Instruction*, PatchableJump& badType) +{ + JumpList slowCases; + + badType = patchableBranch32(NotEqual, regT1, TrustedImm32(DoubleShape)); + + loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3); + slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength()))); + + loadDouble(BaseIndex(regT3, regT2, TimesEight), fpRegT0); + slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0)); + moveDoubleToInts(fpRegT0, regT0, regT1); + + return slowCases; +} + JIT::JumpList JIT::emitArrayStorageGetByVal(Instruction*, PatchableJump& badType) { JumpList slowCases; @@ -270,6 +292,12 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) JITArrayMode mode = chooseArrayMode(profile); switch (mode) { + case JITInt32: + slowCases = emitInt32PutByVal(currentInstruction, badType); + break; + case JITDouble: + slowCases = emitDoublePutByVal(currentInstruction, badType); + break; case JITContiguous: slowCases = emitContiguousPutByVal(currentInstruction, badType); break; @@ -289,7 +317,8 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done)); } -JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) +template<IndexingType indexingShape> +JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) { unsigned value = currentInstruction[3].u.operand; ArrayProfile* profile = currentInstruction[4].u.arrayProfile; @@ -303,8 +332,30 @@ JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, Patch Label storeResult = label(); emitLoad(value, regT1, regT0); - store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); - store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + switch (indexingShape) { + case Int32Shape: + slowCases.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag))); + // Fall through. + case ContiguousShape: + store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + break; + case DoubleShape: { + Jump notInt = branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)); + convertInt32ToDouble(regT0, fpRegT0); + Jump ready = jump(); + notInt.link(this); + moveIntsToDouble(regT0, regT1, fpRegT0, fpRegT1); + slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0)); + ready.link(this); + storeDouble(fpRegT0, BaseIndex(regT3, regT2, TimesEight)); + break; + } + default: + CRASH(); + break; + } + Jump done = jump(); outOfBounds.link(this); @@ -364,12 +415,23 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas unsigned base = currentInstruction[1].u.operand; unsigned property = currentInstruction[2].u.operand; unsigned value = currentInstruction[3].u.operand; + ArrayProfile* profile = currentInstruction[4].u.arrayProfile; linkSlowCase(iter); // property int32 check linkSlowCaseIfNotJSCell(iter, base); // base cell check linkSlowCase(iter); // base not array check linkSlowCase(iter); // out of bounds + JITArrayMode mode = chooseArrayMode(profile); + switch (mode) { + case JITInt32: + case JITDouble: + linkSlowCase(iter); // value type check + break; + default: + break; + } + Label slowPath = label(); JITStubCall stubPutByValCall(this, cti_op_put_by_val); diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index 5ddb98dee..521dfacfd 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -1877,6 +1877,11 @@ DEFINE_STUB_FUNCTION(void, optimize) ASSERT(optimizedCodeBlock->getJITType() == JITCode::DFGJIT); if (void* address = DFG::prepareOSREntry(callFrame, optimizedCodeBlock, bytecodeIndex)) { + if (Options::showDFGDisassembly()) { + dataLog( + "Performing OSR from code block %p to code block %p, address %p to %p.\n", + codeBlock, optimizedCodeBlock, (STUB_RETURN_ADDRESS).value(), address); + } #if ENABLE(JIT_VERBOSE_OSR) dataLog("Optimizing %p succeeded, performing OSR after a delay of %u.\n", codeBlock, codeBlock->optimizationDelayCounter()); #endif @@ -2228,21 +2233,21 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_array) { STUB_INIT_STACK_FRAME(stackFrame); - return constructArray(stackFrame.callFrame, reinterpret_cast<JSValue*>(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()]), stackFrame.args[1].int32()); + return constructArray(stackFrame.callFrame, stackFrame.args[2].arrayAllocationProfile(), reinterpret_cast<JSValue*>(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()]), stackFrame.args[1].int32()); } DEFINE_STUB_FUNCTION(JSObject*, op_new_array_with_size) { STUB_INIT_STACK_FRAME(stackFrame); - return constructArrayWithSizeQuirk(stackFrame.callFrame, stackFrame.callFrame->lexicalGlobalObject(), stackFrame.args[0].jsValue()); + return constructArrayWithSizeQuirk(stackFrame.callFrame, stackFrame.args[1].arrayAllocationProfile(), stackFrame.callFrame->lexicalGlobalObject(), stackFrame.args[0].jsValue()); } DEFINE_STUB_FUNCTION(JSObject*, op_new_array_buffer) { STUB_INIT_STACK_FRAME(stackFrame); - return constructArray(stackFrame.callFrame, stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32()); + return constructArray(stackFrame.callFrame, stackFrame.args[2].arrayAllocationProfile(), stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32()); } DEFINE_STUB_FUNCTION(void, op_init_global_const_check) @@ -2470,7 +2475,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val) JSValue baseValue = stackFrame.args[0].jsValue(); JSValue subscript = stackFrame.args[1].jsValue(); JSValue value = stackFrame.args[2].jsValue(); - + if (baseValue.isObject() && subscript.isInt32()) { // See if it's worth optimizing at all. JSObject* object = asObject(baseValue); diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h index 5761236b1..3bf13bbdf 100644 --- a/Source/JavaScriptCore/jit/JITStubs.h +++ b/Source/JavaScriptCore/jit/JITStubs.h @@ -45,6 +45,7 @@ namespace JSC { struct StructureStubInfo; + class ArrayAllocationProfile; class CodeBlock; class ExecutablePool; class FunctionExecutable; @@ -85,6 +86,7 @@ namespace JSC { ReturnAddressPtr returnAddress() { return ReturnAddressPtr(asPointer); } ResolveOperations* resolveOperations() { return static_cast<ResolveOperations*>(asPointer); } PutToBaseOperation* putToBaseOperation() { return static_cast<PutToBaseOperation*>(asPointer); } + ArrayAllocationProfile* arrayAllocationProfile() { return static_cast<ArrayAllocationProfile*>(asPointer); } }; struct TrampolineStructure { diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp index b8cf49da6..07a05b0c9 100644 --- a/Source/JavaScriptCore/jsc.cpp +++ b/Source/JavaScriptCore/jsc.cpp @@ -22,10 +22,10 @@ #include "config.h" -#include "ButterflyInlineMethods.h" +#include "ButterflyInlines.h" #include "BytecodeGenerator.h" #include "Completion.h" -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "ExceptionHelpers.h" #include "HeapStatistics.h" #include "InitializeThreading.h" @@ -231,7 +231,7 @@ protected: addConstructableFunction(globalData, "Float32Array", constructJSFloat32Array, 1); addConstructableFunction(globalData, "Float64Array", constructJSFloat64Array, 1); - JSArray* array = constructEmptyArray(globalExec()); + JSArray* array = constructEmptyArray(globalExec(), 0); for (size_t i = 0; i < arguments.size(); ++i) array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i])); putDirect(globalData, Identifier(globalExec(), "arguments"), array); diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp index ba44bf404..8a578ffac 100644 --- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp +++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp @@ -275,7 +275,7 @@ inline bool shouldJIT(ExecState* exec) // Returns true if we should try to OSR. inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec) { - codeBlock->updateAllPredictions(); + codeBlock->updateAllValueProfilePredictions(); if (!codeBlock->checkIfJITThresholdReached()) { #if ENABLE(JIT_VERBOSE_OSR) @@ -510,19 +510,19 @@ LLINT_SLOW_PATH_DECL(slow_path_new_object) LLINT_SLOW_PATH_DECL(slow_path_new_array) { LLINT_BEGIN(); - LLINT_RETURN(constructArray(exec, bitwise_cast<JSValue*>(&LLINT_OP(2)), pc[3].u.operand)); + LLINT_RETURN(constructArray(exec, pc[4].u.arrayAllocationProfile, bitwise_cast<JSValue*>(&LLINT_OP(2)), pc[3].u.operand)); } LLINT_SLOW_PATH_DECL(slow_path_new_array_with_size) { LLINT_BEGIN(); - LLINT_RETURN(constructArrayWithSizeQuirk(exec, exec->lexicalGlobalObject(), LLINT_OP_C(2).jsValue())); + LLINT_RETURN(constructArrayWithSizeQuirk(exec, pc[3].u.arrayAllocationProfile, exec->lexicalGlobalObject(), LLINT_OP_C(2).jsValue())); } LLINT_SLOW_PATH_DECL(slow_path_new_array_buffer) { LLINT_BEGIN(); - LLINT_RETURN(constructArray(exec, exec->codeBlock()->constantBuffer(pc[2].u.operand), pc[3].u.operand)); + LLINT_RETURN(constructArray(exec, pc[4].u.arrayAllocationProfile, exec->codeBlock()->constantBuffer(pc[2].u.operand), pc[3].u.operand)); } LLINT_SLOW_PATH_DECL(slow_path_new_regexp) diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm index ba5b67df4..00d5c4f6f 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm @@ -88,10 +88,13 @@ else end # Constant for reasoning about butterflies. -const IsArray = 1 -const IndexingShapeMask = 30 -const ContiguousShape = 26 -const ArrayStorageShape = 28 +const IsArray = 1 +const IndexingShapeMask = 30 +const NoIndexingShape = 0 +const Int32Shape = 20 +const DoubleShape = 22 +const ContiguousShape = 26 +const ArrayStorageShape = 28 const SlowPutArrayStorageShape = 30 # Type constants. @@ -462,19 +465,19 @@ end _llint_op_new_array: traceExecution() callSlowPath(_llint_slow_path_new_array) - dispatch(4) + dispatch(5) _llint_op_new_array_with_size: traceExecution() callSlowPath(_llint_slow_path_new_array_with_size) - dispatch(3) + dispatch(4) _llint_op_new_array_buffer: traceExecution() callSlowPath(_llint_slow_path_new_array_buffer) - dispatch(4) + dispatch(5) _llint_op_new_regexp: diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm index ffb146247..e3ef909f5 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm @@ -1185,7 +1185,9 @@ _llint_op_get_by_val: loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow) loadp JSObject::m_butterfly[t0], t3 andi IndexingShapeMask, t2 + bieq t2, Int32Shape, .opGetByValIsContiguous bineq t2, ContiguousShape, .opGetByValNotContiguous +.opGetByValIsContiguous: biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow loadi TagOffset[t3, t1, 8], t2 @@ -1193,6 +1195,16 @@ _llint_op_get_by_val: jmp .opGetByValDone .opGetByValNotContiguous: + bineq t2, DoubleShape, .opGetByValNotDouble + biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow + loadd [t3, t1, 8], ft0 + bdnequn ft0, ft0, .opGetByValSlow + # FIXME: This could be massively optimized. + fd2ii ft0, t1, t2 + loadi 4[PC], t0 + jmp .opGetByValNotEmpty + +.opGetByValNotDouble: subi ArrayStorageShape, t2 bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t3], .opGetByValSlow @@ -1202,6 +1214,7 @@ _llint_op_get_by_val: .opGetByValDone: loadi 4[PC], t0 bieq t2, EmptyValueTag, .opGetByValSlow +.opGetByValNotEmpty: storei t2, TagOffset[cfr, t0, 8] storei t1, PayloadOffset[cfr, t0, 8] loadi 20[PC], t0 @@ -1270,6 +1283,24 @@ _llint_op_get_by_pname: dispatch(7) +macro contiguousPutByVal(storeCallback) + biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .outOfBounds +.storeResult: + loadi 12[PC], t2 + storeCallback(t2, t1, t0, t3) + dispatch(5) + +.outOfBounds: + biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow + if VALUE_PROFILER + loadp 16[PC], t2 + storeb 1, ArrayProfile::m_mayStoreToHole[t2] + end + addi 1, t3, t2 + storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0] + jmp .storeResult +end + _llint_op_put_by_val: traceExecution() loadi 4[PC], t0 @@ -1281,26 +1312,42 @@ _llint_op_put_by_val: loadConstantOrVariablePayload(t0, Int32Tag, t3, .opPutByValSlow) loadp JSObject::m_butterfly[t1], t0 andi IndexingShapeMask, t2 - bineq t2, ContiguousShape, .opPutByValNotContiguous + bineq t2, Int32Shape, .opPutByValNotInt32 + contiguousPutByVal( + macro (operand, scratch, base, index) + loadConstantOrVariablePayload(operand, Int32Tag, scratch, .opPutByValSlow) + storei Int32Tag, TagOffset[base, index, 8] + storei scratch, PayloadOffset[base, index, 8] + end) - biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .opPutByValContiguousOutOfBounds -.opPutByValContiguousStoreResult: - loadi 12[PC], t2 - loadConstantOrVariable2Reg(t2, t1, t2) - writeBarrier(t1, t2) - storei t1, TagOffset[t0, t3, 8] - storei t2, PayloadOffset[t0, t3, 8] - dispatch(5) +.opPutByValNotInt32: + bineq t2, DoubleShape, .opPutByValNotDouble + contiguousPutByVal( + macro (operand, scratch, base, index) + const tag = scratch + const payload = operand + loadConstantOrVariable2Reg(operand, tag, payload) + bineq tag, Int32Tag, .notInt + ci2d payload, ft0 + jmp .ready + .notInt: + fii2d payload, tag, ft0 + bdnequn ft0, ft0, .opPutByValSlow + .ready: + stored ft0, [base, index, 8] + end) -.opPutByValContiguousOutOfBounds: - biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow - if VALUE_PROFILER - loadp 16[PC], t1 - storeb 1, ArrayProfile::m_mayStoreToHole[t1] - end - addi 1, t3, t2 - storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0] - jmp .opPutByValContiguousStoreResult +.opPutByValNotDouble: + bineq t2, ContiguousShape, .opPutByValNotContiguous + contiguousPutByVal( + macro (operand, scratch, base, index) + const tag = scratch + const payload = operand + loadConstantOrVariable2Reg(operand, tag, payload) + writeBarrier(tag, payload) + storei tag, TagOffset[base, index, 8] + storei payload, PayloadOffset[base, index, 8] + end) .opPutByValNotContiguous: bineq t2, ArrayStorageShape, .opPutByValSlow diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm index c9900b343..d8a293337 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm @@ -1025,7 +1025,9 @@ _llint_op_get_by_val: sxi2q t1, t1 loadp JSObject::m_butterfly[t0], t3 andi IndexingShapeMask, t2 + bieq t2, Int32Shape, .opGetByValIsContiguous bineq t2, ContiguousShape, .opGetByValNotContiguous +.opGetByValIsContiguous: biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow loadisFromInstruction(1, t0) @@ -1034,6 +1036,16 @@ _llint_op_get_by_val: jmp .opGetByValDone .opGetByValNotContiguous: + bineq t2, DoubleShape, .opGetByValNotDouble + biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow + loadis 8[PB, PC, 8], t0 + loadd [t3, t1, 8], ft0 + bdnequn ft0, ft0, .opGetByValSlow + fd2q ft0, t2 + subq tagTypeNumber, t2 + jmp .opGetByValDone + +.opGetByValNotDouble: subi ArrayStorageShape, t2 bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t3], .opGetByValSlow @@ -1109,6 +1121,24 @@ _llint_op_get_by_pname: dispatch(7) +macro contiguousPutByVal(storeCallback) + biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .outOfBounds +.storeResult: + loadisFromInstruction(3, t2) + storeCallback(t2, t1, [t0, t3, 8]) + dispatch(5) + +.outOfBounds: + biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow + if VALUE_PROFILER + loadp 32[PB, PC, 8], t2 + storeb 1, ArrayProfile::m_mayStoreToHole[t2] + end + addi 1, t3, t2 + storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0] + jmp .storeResult +end + _llint_op_put_by_val: traceExecution() loadisFromInstruction(1, t0) @@ -1121,25 +1151,38 @@ _llint_op_put_by_val: sxi2q t3, t3 loadp JSObject::m_butterfly[t1], t0 andi IndexingShapeMask, t2 - bineq t2, ContiguousShape, .opPutByValNotContiguous - - biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .opPutByValContiguousOutOfBounds -.opPutByValContiguousStoreResult: - loadisFromInstruction(3, t2) - loadConstantOrVariable(t2, t1) - writeBarrier(t1) - storeq t1, [t0, t3, 8] - dispatch(5) + bineq t2, Int32Shape, .opPutByValNotInt32 + contiguousPutByVal( + macro (operand, scratch, address) + loadConstantOrVariable(operand, scratch) + bpb scratch, tagTypeNumber, .opPutByValSlow + storep scratch, address + end) -.opPutByValContiguousOutOfBounds: - biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow - if VALUE_PROFILER - loadpFromInstruction(4, t2) - storeb 1, ArrayProfile::m_mayStoreToHole[t2] - end - addi 1, t3, t2 - storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0] - jmp .opPutByValContiguousStoreResult +.opPutByValNotInt32: + bineq t2, DoubleShape, .opPutByValNotDouble + contiguousPutByVal( + macro (operand, scratch, address) + loadConstantOrVariable(operand, scratch) + bqb scratch, tagTypeNumber, .notInt + ci2d scratch, ft0 + jmp .ready + .notInt: + addp tagTypeNumber, scratch + fq2d scratch, ft0 + bdnequn ft0, ft0, .opPutByValSlow + .ready: + stored ft0, address + end) + +.opPutByValNotDouble: + bineq t2, ContiguousShape, .opPutByValNotContiguous + contiguousPutByVal( + macro (operand, scratch, address) + loadConstantOrVariable(operand, scratch) + writeBarrier(scratch) + storep scratch, address + end) .opPutByValNotContiguous: bineq t2, ArrayStorageShape, .opPutByValSlow diff --git a/Source/JavaScriptCore/offlineasm/x86.rb b/Source/JavaScriptCore/offlineasm/x86.rb index 67cbd14b0..f78b43912 100644 --- a/Source/JavaScriptCore/offlineasm/x86.rb +++ b/Source/JavaScriptCore/offlineasm/x86.rb @@ -764,11 +764,16 @@ class Instruction when "ci2d" $asm.puts "cvtsi2sd #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:double)}" when "bdeq" - isUnordered = LocalLabel.unique("bdeq") $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" - $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}" - $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}" - isUnordered.lower("X86") + if operands[0] == operands[1] + # This is just a jump ordered, which is a jnp. + $asm.puts "jnp #{operands[2].asmLabel}" + else + isUnordered = LocalLabel.unique("bdeq") + $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}" + $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}" + isUnordered.lower("X86") + end when "bdneq" handleX86DoubleBranch("jne", :normal) when "bdgt" @@ -782,14 +787,19 @@ class Instruction when "bdequn" handleX86DoubleBranch("je", :normal) when "bdnequn" - isUnordered = LocalLabel.unique("bdnequn") - isEqual = LocalLabel.unique("bdnequn") $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" - $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}" - $asm.puts "je #{LabelReference.new(codeOrigin, isEqual).asmLabel}" - isUnordered.lower("X86") - $asm.puts "jmp #{operands[2].asmLabel}" - isEqual.lower("X86") + if operands[0] == operands[1] + # This is just a jump unordered, which is a jp. + $asm.puts "jp #{operands[2].asmLabel}" + else + isUnordered = LocalLabel.unique("bdnequn") + isEqual = LocalLabel.unique("bdnequn") + $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}" + $asm.puts "je #{LabelReference.new(codeOrigin, isEqual).asmLabel}" + isUnordered.lower("X86") + $asm.puts "jmp #{operands[2].asmLabel}" + isEqual.lower("X86") + end when "bdgtun" handleX86DoubleBranch("jb", :reverse) when "bdgtequn" @@ -1115,7 +1125,7 @@ class Instruction $asm.puts "movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}" $asm.puts "movsd #{operands[0].x86Operand(:double)}, %xmm7" $asm.puts "psrlq $32, %xmm7" - $asm.puts "movsd %xmm7, #{operands[2].x86Operand(:int)}" + $asm.puts "movd %xmm7, #{operands[2].x86Operand(:int)}" when "fq2d" $asm.puts "movd #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}" when "fd2q" diff --git a/Source/JavaScriptCore/runtime/ArgList.h b/Source/JavaScriptCore/runtime/ArgList.h index 29010b1ee..1fb1ce911 100644 --- a/Source/JavaScriptCore/runtime/ArgList.h +++ b/Source/JavaScriptCore/runtime/ArgList.h @@ -29,153 +29,153 @@ namespace JSC { - class SlotVisitor; - - class MarkedArgumentBuffer { - WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer); - friend class JSGlobalData; - friend class ArgList; - - private: - static const size_t inlineCapacity = 8; - typedef Vector<Register, inlineCapacity> VectorType; - typedef HashSet<MarkedArgumentBuffer*> ListSet; - - public: - // Constructor for a read-write list, to which you may append values. - // FIXME: Remove all clients of this API, then remove this API. - MarkedArgumentBuffer() - : m_size(0) - , m_capacity(inlineCapacity) - , m_buffer(&m_inlineBuffer[m_capacity - 1]) - , m_markSet(0) - { - } - - ~MarkedArgumentBuffer() - { - if (m_markSet) - m_markSet->remove(this); - - if (EncodedJSValue* base = mallocBase()) - delete [] base; - } - - size_t size() const { return m_size; } - bool isEmpty() const { return !m_size; } - - JSValue at(int i) const - { - if (i >= m_size) - return jsUndefined(); - - return JSValue::decode(slotFor(i)); - } - - void clear() - { - m_size = 0; - } - - void append(JSValue v) - { - if (m_size >= m_capacity) - return slowAppend(v); - - slotFor(m_size) = JSValue::encode(v); - ++m_size; - } - - void removeLast() - { - ASSERT(m_size); - m_size--; - } - - JSValue last() - { - ASSERT(m_size); - return JSValue::decode(slotFor(m_size - 1)); - } +class SlotVisitor; + +class MarkedArgumentBuffer { + WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer); + friend class JSGlobalData; + friend class ArgList; + +private: + static const size_t inlineCapacity = 8; + typedef Vector<Register, inlineCapacity> VectorType; + typedef HashSet<MarkedArgumentBuffer*> ListSet; + +public: + // Constructor for a read-write list, to which you may append values. + // FIXME: Remove all clients of this API, then remove this API. + MarkedArgumentBuffer() + : m_size(0) + , m_capacity(inlineCapacity) + , m_buffer(&m_inlineBuffer[m_capacity - 1]) + , m_markSet(0) + { + } + + ~MarkedArgumentBuffer() + { + if (m_markSet) + m_markSet->remove(this); + + if (EncodedJSValue* base = mallocBase()) + delete [] base; + } + + size_t size() const { return m_size; } + bool isEmpty() const { return !m_size; } + + JSValue at(int i) const + { + if (i >= m_size) + return jsUndefined(); + + return JSValue::decode(slotFor(i)); + } + + void clear() + { + m_size = 0; + } + + void append(JSValue v) + { + if (m_size >= m_capacity) + return slowAppend(v); + + slotFor(m_size) = JSValue::encode(v); + ++m_size; + } + + void removeLast() + { + ASSERT(m_size); + m_size--; + } + + JSValue last() + { + ASSERT(m_size); + return JSValue::decode(slotFor(m_size - 1)); + } - static void markLists(HeapRootVisitor&, ListSet&); + static void markLists(HeapRootVisitor&, ListSet&); - private: - JS_EXPORT_PRIVATE void slowAppend(JSValue); +private: + JS_EXPORT_PRIVATE void slowAppend(JSValue); - EncodedJSValue& slotFor(int item) const - { - return m_buffer[-item]; - } + EncodedJSValue& slotFor(int item) const + { + return m_buffer[-item]; + } - EncodedJSValue* mallocBase() - { - if (m_capacity == static_cast<int>(inlineCapacity)) - return 0; - return &slotFor(m_capacity - 1); - } + EncodedJSValue* mallocBase() + { + if (m_capacity == static_cast<int>(inlineCapacity)) + return 0; + return &slotFor(m_capacity - 1); + } - int m_size; - int m_capacity; - EncodedJSValue m_inlineBuffer[inlineCapacity]; - EncodedJSValue* m_buffer; - ListSet* m_markSet; - - private: - // Prohibits new / delete, which would break GC. - void* operator new(size_t size) - { - return fastMalloc(size); - } - void operator delete(void* p) - { - fastFree(p); - } - - void* operator new[](size_t); - void operator delete[](void*); - - void* operator new(size_t, void*); - void operator delete(void*, size_t); - }; - - class ArgList { - friend class JIT; - public: - ArgList() - : m_args(0) - , m_argCount(0) - { - } - - ArgList(ExecState* exec) - : m_args(reinterpret_cast<JSValue*>(&exec[CallFrame::argumentOffset(0)])) - , m_argCount(exec->argumentCount()) - { - } - - ArgList(const MarkedArgumentBuffer& args) - : m_args(reinterpret_cast<JSValue*>(args.m_buffer)) - , m_argCount(args.size()) - { - } - - JSValue at(int i) const - { - if (i >= m_argCount) - return jsUndefined(); - return m_args[-i]; - } - - bool isEmpty() const { return !m_argCount; } - size_t size() const { return m_argCount; } + int m_size; + int m_capacity; + EncodedJSValue m_inlineBuffer[inlineCapacity]; + EncodedJSValue* m_buffer; + ListSet* m_markSet; + +private: + // Prohibits new / delete, which would break GC. + void* operator new(size_t size) + { + return fastMalloc(size); + } + void operator delete(void* p) + { + fastFree(p); + } + + void* operator new[](size_t); + void operator delete[](void*); + + void* operator new(size_t, void*); + void operator delete(void*, size_t); +}; + +class ArgList { + friend class JIT; +public: + ArgList() + : m_args(0) + , m_argCount(0) + { + } + + ArgList(ExecState* exec) + : m_args(reinterpret_cast<JSValue*>(&exec[CallFrame::argumentOffset(0)])) + , m_argCount(exec->argumentCount()) + { + } + + ArgList(const MarkedArgumentBuffer& args) + : m_args(reinterpret_cast<JSValue*>(args.m_buffer)) + , m_argCount(args.size()) + { + } + + JSValue at(int i) const + { + if (i >= m_argCount) + return jsUndefined(); + return m_args[-i]; + } + + bool isEmpty() const { return !m_argCount; } + size_t size() const { return m_argCount; } - JS_EXPORT_PRIVATE void getSlice(int startIndex, ArgList& result) const; + JS_EXPORT_PRIVATE void getSlice(int startIndex, ArgList& result) const; - private: - JSValue* m_args; - int m_argCount; - }; +private: + JSValue* m_args; + int m_argCount; +}; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h index 7961d4bc8..8ae991422 100644 --- a/Source/JavaScriptCore/runtime/Arguments.h +++ b/Source/JavaScriptCore/runtime/Arguments.h @@ -34,246 +34,246 @@ namespace JSC { - class Arguments : public JSDestructibleObject { - friend class JIT; - friend class DFG::SpeculativeJIT; - public: - typedef JSDestructibleObject Base; - - static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame) - { - Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame); - arguments->finishCreation(callFrame); - return arguments; - } - - static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame, InlineCallFrame* inlineCallFrame) - { - Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame); - arguments->finishCreation(callFrame, inlineCallFrame); - return arguments; - } - - enum { MaxArguments = 0x10000 }; - - private: - enum NoParametersType { NoParameters }; - - Arguments(CallFrame*); - Arguments(CallFrame*, NoParametersType); - - void tearOffForInlineCallFrame(JSGlobalData& globalData, Register*, InlineCallFrame*); +class Arguments : public JSDestructibleObject { + friend class JIT; + friend class DFG::SpeculativeJIT; +public: + typedef JSDestructibleObject Base; - public: - static const ClassInfo s_info; - - static void visitChildren(JSCell*, SlotVisitor&); - - void fillArgList(ExecState*, MarkedArgumentBuffer&); - - uint32_t length(ExecState* exec) const - { - if (UNLIKELY(m_overrodeLength)) - return get(exec, exec->propertyNames().length).toUInt32(exec); - return m_numArguments; - } - - void copyToArguments(ExecState*, CallFrame*, uint32_t length); - void tearOff(CallFrame*); - void tearOff(CallFrame*, InlineCallFrame*); - bool isTornOff() const { return m_registerArray; } - void didTearOffActivation(ExecState*, JSActivation*); - - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); - } - - protected: - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; - - void finishCreation(CallFrame*); - void finishCreation(CallFrame*, InlineCallFrame*); - - private: - static void destroy(JSCell*); - static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); - static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - static bool deleteProperty(JSCell*, ExecState*, PropertyName); - static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); - static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); - void createStrictModeCallerIfNecessary(ExecState*); - void createStrictModeCalleeIfNecessary(ExecState*); - - bool isArgument(size_t); - bool trySetArgument(JSGlobalData&, size_t argument, JSValue); - JSValue tryGetArgument(size_t argument); - bool isDeletedArgument(size_t); - bool tryDeleteArgument(size_t); - WriteBarrierBase<Unknown>& argument(size_t); - void allocateSlowArguments(); - - void init(CallFrame*); - - WriteBarrier<JSActivation> m_activation; - - unsigned m_numArguments; - - // We make these full byte booleans to make them easy to test from the JIT, - // and because even if they were single-bit booleans we still wouldn't save - // any space. - bool m_overrodeLength; - bool m_overrodeCallee; - bool m_overrodeCaller; - bool m_isStrictMode; - - WriteBarrierBase<Unknown>* m_registers; - OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray; - - OwnArrayPtr<SlowArgument> m_slowArguments; - - WriteBarrier<JSFunction> m_callee; - }; - - Arguments* asArguments(JSValue); - - inline Arguments* asArguments(JSValue value) + static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame) { - ASSERT(asObject(value)->inherits(&Arguments::s_info)); - return static_cast<Arguments*>(asObject(value)); + Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame); + arguments->finishCreation(callFrame); + return arguments; } - - inline Arguments::Arguments(CallFrame* callFrame) - : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) + + static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame, InlineCallFrame* inlineCallFrame) { + Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame); + arguments->finishCreation(callFrame, inlineCallFrame); + return arguments; } - inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) - : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) - { - } + enum { MaxArguments = 0x10000 }; - inline void Arguments::allocateSlowArguments() - { - if (m_slowArguments) - return; - m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]); - for (size_t i = 0; i < m_numArguments; ++i) { - ASSERT(m_slowArguments[i].status == SlowArgument::Normal); - m_slowArguments[i].index = CallFrame::argumentOffset(i); - } - } +private: + enum NoParametersType { NoParameters }; + + Arguments(CallFrame*); + Arguments(CallFrame*, NoParametersType); + + void tearOffForInlineCallFrame(JSGlobalData& globalData, Register*, InlineCallFrame*); - inline bool Arguments::tryDeleteArgument(size_t argument) - { - if (!isArgument(argument)) - return false; - allocateSlowArguments(); - m_slowArguments[argument].status = SlowArgument::Deleted; - return true; - } +public: + static const ClassInfo s_info; - inline bool Arguments::trySetArgument(JSGlobalData& globalData, size_t argument, JSValue value) - { - if (!isArgument(argument)) - return false; - this->argument(argument).set(globalData, this, value); - return true; - } + static void visitChildren(JSCell*, SlotVisitor&); - inline JSValue Arguments::tryGetArgument(size_t argument) - { - if (!isArgument(argument)) - return JSValue(); - return this->argument(argument).get(); - } + void fillArgList(ExecState*, MarkedArgumentBuffer&); - inline bool Arguments::isDeletedArgument(size_t argument) + uint32_t length(ExecState* exec) const { - if (argument >= m_numArguments) - return false; - if (!m_slowArguments) - return false; - if (m_slowArguments[argument].status != SlowArgument::Deleted) - return false; - return true; + if (UNLIKELY(m_overrodeLength)) + return get(exec, exec->propertyNames().length).toUInt32(exec); + return m_numArguments; } - - inline bool Arguments::isArgument(size_t argument) - { - if (argument >= m_numArguments) - return false; - if (m_slowArguments && m_slowArguments[argument].status == SlowArgument::Deleted) - return false; - return true; + + void copyToArguments(ExecState*, CallFrame*, uint32_t length); + void tearOff(CallFrame*); + void tearOff(CallFrame*, InlineCallFrame*); + bool isTornOff() const { return m_registerArray; } + void didTearOffActivation(ExecState*, JSActivation*); + + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } - - inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument) - { - ASSERT(isArgument(argument)); - if (!m_slowArguments) - return m_registers[CallFrame::argumentOffset(argument)]; - - int index = m_slowArguments[argument].index; - if (!m_activation || m_slowArguments[argument].status != SlowArgument::Captured) - return m_registers[index]; - - return m_activation->registerAt(index); + +protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; + + void finishCreation(CallFrame*); + void finishCreation(CallFrame*, InlineCallFrame*); + +private: + static void destroy(JSCell*); + static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); + static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); + static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + static bool deleteProperty(JSCell*, ExecState*, PropertyName); + static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); + static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); + void createStrictModeCallerIfNecessary(ExecState*); + void createStrictModeCalleeIfNecessary(ExecState*); + + bool isArgument(size_t); + bool trySetArgument(JSGlobalData&, size_t argument, JSValue); + JSValue tryGetArgument(size_t argument); + bool isDeletedArgument(size_t); + bool tryDeleteArgument(size_t); + WriteBarrierBase<Unknown>& argument(size_t); + void allocateSlowArguments(); + + void init(CallFrame*); + + WriteBarrier<JSActivation> m_activation; + + unsigned m_numArguments; + + // We make these full byte booleans to make them easy to test from the JIT, + // and because even if they were single-bit booleans we still wouldn't save + // any space. + bool m_overrodeLength; + bool m_overrodeCallee; + bool m_overrodeCaller; + bool m_isStrictMode; + + WriteBarrierBase<Unknown>* m_registers; + OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray; + + OwnArrayPtr<SlowArgument> m_slowArguments; + + WriteBarrier<JSFunction> m_callee; +}; + +Arguments* asArguments(JSValue); + +inline Arguments* asArguments(JSValue value) +{ + ASSERT(asObject(value)->inherits(&Arguments::s_info)); + return static_cast<Arguments*>(asObject(value)); +} + +inline Arguments::Arguments(CallFrame* callFrame) + : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) +{ +} + +inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) + : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) +{ +} + +inline void Arguments::allocateSlowArguments() +{ + if (m_slowArguments) + return; + m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]); + for (size_t i = 0; i < m_numArguments; ++i) { + ASSERT(m_slowArguments[i].status == SlowArgument::Normal); + m_slowArguments[i].index = CallFrame::argumentOffset(i); } - - inline void Arguments::finishCreation(CallFrame* callFrame) - { - Base::finishCreation(callFrame->globalData()); - ASSERT(inherits(&s_info)); - - JSFunction* callee = jsCast<JSFunction*>(callFrame->callee()); - m_numArguments = callFrame->argumentCount(); - m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()); - m_callee.set(callFrame->globalData(), this, callee); - m_overrodeLength = false; - m_overrodeCallee = false; - m_overrodeCaller = false; - m_isStrictMode = callFrame->codeBlock()->isStrictMode(); - - SharedSymbolTable* symbolTable = callFrame->codeBlock()->symbolTable(); - const SlowArgument* slowArguments = symbolTable->slowArguments(); - if (slowArguments) { - allocateSlowArguments(); - size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount()); - for (size_t i = 0; i < count; ++i) - m_slowArguments[i] = slowArguments[i]; - } - - // The bytecode generator omits op_tear_off_activation in cases of no - // declared parameters, so we need to tear off immediately. - if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) - tearOff(callFrame); +} + +inline bool Arguments::tryDeleteArgument(size_t argument) +{ + if (!isArgument(argument)) + return false; + allocateSlowArguments(); + m_slowArguments[argument].status = SlowArgument::Deleted; + return true; +} + +inline bool Arguments::trySetArgument(JSGlobalData& globalData, size_t argument, JSValue value) +{ + if (!isArgument(argument)) + return false; + this->argument(argument).set(globalData, this, value); + return true; +} + +inline JSValue Arguments::tryGetArgument(size_t argument) +{ + if (!isArgument(argument)) + return JSValue(); + return this->argument(argument).get(); +} + +inline bool Arguments::isDeletedArgument(size_t argument) +{ + if (argument >= m_numArguments) + return false; + if (!m_slowArguments) + return false; + if (m_slowArguments[argument].status != SlowArgument::Deleted) + return false; + return true; +} + +inline bool Arguments::isArgument(size_t argument) +{ + if (argument >= m_numArguments) + return false; + if (m_slowArguments && m_slowArguments[argument].status == SlowArgument::Deleted) + return false; + return true; +} + +inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument) +{ + ASSERT(isArgument(argument)); + if (!m_slowArguments) + return m_registers[CallFrame::argumentOffset(argument)]; + + int index = m_slowArguments[argument].index; + if (!m_activation || m_slowArguments[argument].status != SlowArgument::Captured) + return m_registers[index]; + + return m_activation->registerAt(index); +} + +inline void Arguments::finishCreation(CallFrame* callFrame) +{ + Base::finishCreation(callFrame->globalData()); + ASSERT(inherits(&s_info)); + + JSFunction* callee = jsCast<JSFunction*>(callFrame->callee()); + m_numArguments = callFrame->argumentCount(); + m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()); + m_callee.set(callFrame->globalData(), this, callee); + m_overrodeLength = false; + m_overrodeCallee = false; + m_overrodeCaller = false; + m_isStrictMode = callFrame->codeBlock()->isStrictMode(); + + SharedSymbolTable* symbolTable = callFrame->codeBlock()->symbolTable(); + const SlowArgument* slowArguments = symbolTable->slowArguments(); + if (slowArguments) { + allocateSlowArguments(); + size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount()); + for (size_t i = 0; i < count; ++i) + m_slowArguments[i] = slowArguments[i]; } - inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame) - { - Base::finishCreation(callFrame->globalData()); - ASSERT(inherits(&s_info)); - - JSFunction* callee = inlineCallFrame->callee.get(); - m_numArguments = inlineCallFrame->arguments.size() - 1; - m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset; - m_callee.set(callFrame->globalData(), this, callee); - m_overrodeLength = false; - m_overrodeCallee = false; - m_overrodeCaller = false; - m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode(); - ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)->slowArguments()); - - // The bytecode generator omits op_tear_off_activation in cases of no - // declared parameters, so we need to tear off immediately. - if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) - tearOff(callFrame, inlineCallFrame); - } + // The bytecode generator omits op_tear_off_activation in cases of no + // declared parameters, so we need to tear off immediately. + if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) + tearOff(callFrame); +} + +inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame) +{ + Base::finishCreation(callFrame->globalData()); + ASSERT(inherits(&s_info)); + + JSFunction* callee = inlineCallFrame->callee.get(); + m_numArguments = inlineCallFrame->arguments.size() - 1; + m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset; + m_callee.set(callFrame->globalData(), this, callee); + m_overrodeLength = false; + m_overrodeCallee = false; + m_overrodeCaller = false; + m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode(); + ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)->slowArguments()); + + // The bytecode generator omits op_tear_off_activation in cases of no + // declared parameters, so we need to tear off immediately. + if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) + tearOff(callFrame, inlineCallFrame); +} } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp index 5c2cd7167..a3fce45f2 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -25,8 +25,8 @@ #include "ArrayConstructor.h" #include "ArrayPrototype.h" -#include "ButterflyInlineMethods.h" -#include "CopiedSpaceInlineMethods.h" +#include "ButterflyInlines.h" +#include "CopiedSpaceInlines.h" #include "Error.h" #include "ExceptionHelpers.h" #include "JSArray.h" @@ -77,15 +77,15 @@ bool ArrayConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exe // ------------------------------ Functions --------------------------- -JSObject* constructArrayWithSizeQuirk(ExecState* exec, JSGlobalObject* globalObject, JSValue length) +JSObject* constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length) { if (!length.isNumber()) - return constructArray(exec, globalObject, &length, 1); + return constructArray(exec, profile, globalObject, &length, 1); uint32_t n = length.toUInt32(exec); if (n != length.toNumber(exec)) return throwError(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer."))); - return constructEmptyArray(exec, globalObject, n); + return constructEmptyArray(exec, profile, globalObject, n); } static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args) @@ -94,10 +94,10 @@ static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgLi // a single numeric argument denotes the array size (!) if (args.size() == 1) - return constructArrayWithSizeQuirk(exec, globalObject, args.at(0)); + return constructArrayWithSizeQuirk(exec, 0, globalObject, args.at(0)); // otherwise the array is constructed with the arguments in it - return constructArray(exec, globalObject, args); + return constructArray(exec, 0, globalObject, args); } static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec) diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.h b/Source/JavaScriptCore/runtime/ArrayConstructor.h index dcbf0a1b3..96860b0fc 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.h +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.h @@ -25,42 +25,42 @@ namespace JSC { - class ArrayPrototype; - class JSArray; +class ArrayPrototype; +class JSArray; - class ArrayConstructor : public InternalFunction { - public: - typedef InternalFunction Base; +class ArrayConstructor : public InternalFunction { +public: + typedef InternalFunction Base; - static ArrayConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ArrayPrototype* arrayPrototype) - { - ArrayConstructor* constructor = new (NotNull, allocateCell<ArrayConstructor>(*exec->heap())) ArrayConstructor(globalObject, structure); - constructor->finishCreation(exec, arrayPrototype); - return constructor; - } + static ArrayConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ArrayPrototype* arrayPrototype) + { + ArrayConstructor* constructor = new (NotNull, allocateCell<ArrayConstructor>(*exec->heap())) ArrayConstructor(globalObject, structure); + constructor->finishCreation(exec, arrayPrototype); + return constructor; + } - static 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); - } + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + } - protected: - void finishCreation(ExecState*, ArrayPrototype*); - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags; +protected: + void finishCreation(ExecState*, ArrayPrototype*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags; - private: - ArrayConstructor(JSGlobalObject*, Structure*); - static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); +private: + ArrayConstructor(JSGlobalObject*, Structure*); + static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); + static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); - }; + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); +}; - JSObject* constructArrayWithSizeQuirk(ExecState*, JSGlobalObject*, JSValue); +JSObject* constructArrayWithSizeQuirk(ExecState*, ArrayAllocationProfile*, JSGlobalObject*, JSValue); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index 6975dc778..cc847d8ff 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -24,10 +24,10 @@ #include "config.h" #include "ArrayPrototype.h" -#include "ButterflyInlineMethods.h" +#include "ButterflyInlines.h" #include "CachedCall.h" #include "CodeBlock.h" -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "Interpreter.h" #include "JIT.h" #include "JSStringBuilder.h" @@ -456,7 +456,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - JSArray* arr = constructEmptyArray(exec); + JSArray* arr = constructEmptyArray(exec, 0); unsigned n = 0; JSValue curArg = thisValue.toObject(exec); if (exec->hadException()) @@ -618,7 +618,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec) return JSValue::encode(jsUndefined()); // We return a new array - JSArray* resObj = constructEmptyArray(exec); + JSArray* resObj = constructEmptyArray(exec, 0); JSValue result = resObj; unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length); @@ -733,7 +733,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) return JSValue::encode(jsUndefined()); if (!exec->argumentCount()) - return JSValue::encode(constructEmptyArray(exec)); + return JSValue::encode(constructEmptyArray(exec, 0)); unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length); @@ -748,7 +748,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) deleteCount = static_cast<unsigned>(deleteDouble); } - JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), deleteCount); + JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount); if (!resObj) return JSValue::encode(throwOutOfMemoryError(exec)); @@ -820,7 +820,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec) return throwVMTypeError(exec); JSValue applyThis = exec->argument(1); - JSArray* resultArray = constructEmptyArray(exec); + JSArray* resultArray = constructEmptyArray(exec, 0); unsigned filterIndex = 0; unsigned k = 0; @@ -880,7 +880,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec) JSValue applyThis = exec->argument(1); - JSArray* resultArray = constructEmptyArray(exec, length); + JSArray* resultArray = constructEmptyArray(exec, 0, length); unsigned k = 0; if (callType == CallTypeJS && isJSArray(thisObj)) { JSFunction* f = jsCast<JSFunction*>(function); diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.h b/Source/JavaScriptCore/runtime/ArrayPrototype.h index b33021121..2b83d39b7 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.h +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.h @@ -26,28 +26,28 @@ namespace JSC { - class ArrayPrototype : public JSArray { - private: - ArrayPrototype(JSGlobalObject*, Structure*, Butterfly*); +class ArrayPrototype : public JSArray { +private: + ArrayPrototype(JSGlobalObject*, Structure*, Butterfly*); - public: - typedef JSArray Base; +public: + typedef JSArray Base; - static ArrayPrototype* create(ExecState*, JSGlobalObject*, Structure*); + static ArrayPrototype* create(ExecState*, JSGlobalObject*, Structure*); - static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); + static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); - static 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, ArrayWithArrayStorage); - } + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayWithArrayStorage); + } - protected: - void finishCreation(JSGlobalObject*); - }; +protected: + void finishCreation(JSGlobalObject*); +}; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h index cb93aea8a..4b8d53f7e 100644 --- a/Source/JavaScriptCore/runtime/Butterfly.h +++ b/Source/JavaScriptCore/runtime/Butterfly.h @@ -88,12 +88,18 @@ public: template<typename T> T* indexingPayload() { return reinterpret_cast<T*>(this); } ArrayStorage* arrayStorage() { return indexingPayload<ArrayStorage>(); } + WriteBarrier<Unknown>* contiguousInt32() { return indexingPayload<WriteBarrier<Unknown> >(); } + double* contiguousDouble() { return indexingPayload<double>(); } WriteBarrier<Unknown>* contiguous() { return indexingPayload<WriteBarrier<Unknown> >(); } static Butterfly* fromContiguous(WriteBarrier<Unknown>* contiguous) { return reinterpret_cast<Butterfly*>(contiguous); } + static Butterfly* fromContiguous(double* contiguous) + { + return reinterpret_cast<Butterfly*>(contiguous); + } static ptrdiff_t offsetOfPropertyStorage() { return -static_cast<ptrdiff_t>(sizeof(IndexingHeader)); } static int indexOfPropertyStorage() diff --git a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h b/Source/JavaScriptCore/runtime/ButterflyInlines.h index 86a836bef..9167497a4 100644 --- a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h +++ b/Source/JavaScriptCore/runtime/ButterflyInlines.h @@ -23,12 +23,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ButterflyInlineMethods_h -#define ButterflyInlineMethods_h +#ifndef ButterflyInlines_h +#define ButterflyInlines_h #include "ArrayStorage.h" #include "Butterfly.h" -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "CopyVisitor.h" #include "JSGlobalData.h" #include "Structure.h" @@ -61,8 +61,9 @@ inline Butterfly* Butterfly::create(JSGlobalData& globalData, Structure* structu inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) { + size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); Butterfly* result = fromBase( - visitor.allocateNewSpace(totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)), + visitor.allocateNewSpace(size), preCapacity, propertyCapacity); return result; } @@ -175,5 +176,5 @@ inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots) } // namespace JSC -#endif // ButterflyInlineMethods_h +#endif // ButterflyInlines_h diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp index 4de760e49..068919528 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.cpp +++ b/Source/JavaScriptCore/runtime/CodeCache.cpp @@ -36,7 +36,6 @@ namespace JSC { CodeCache::CodeCache() - : m_randomGenerator(static_cast<uint32_t>(randomNumber() * UINT32_MAX)) { } @@ -67,9 +66,9 @@ UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, Executa CodeBlockKey key = makeCodeBlockKey(source, CacheTypes<UnlinkedCodeBlockType>::codeType, strictness); bool storeInCache = false; if (debuggerMode == DebuggerOff && profilerMode == ProfilerOff) { - CodeBlockIndicesMap::iterator result = m_cachedCodeBlockIndices.find(key); - if (result != m_cachedCodeBlockIndices.end()) { - UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(m_cachedCodeBlocks[result->value].second.get()); + const Strong<UnlinkedCodeBlock>* result = m_cachedCodeBlocks.find(key); + if (result) { + UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(result->get()); unsigned firstLine = source.firstLine() + unlinkedCode->firstLine(); executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount()); return unlinkedCode; @@ -91,14 +90,8 @@ UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, Executa if (error.m_type != ParserError::ErrorNone) return 0; - if (storeInCache) { - size_t index = m_randomGenerator.getUint32() % kMaxCodeBlockEntries; - if (m_cachedCodeBlocks[index].second) - m_cachedCodeBlockIndices.remove(m_cachedCodeBlocks[index].first); - m_cachedCodeBlockIndices.set(key, index); - m_cachedCodeBlocks[index].second.set(globalData, unlinkedCode); - m_cachedCodeBlocks[index].first = key; - } + if (storeInCache) + m_cachedCodeBlocks.add(key, Strong<UnlinkedCodeBlock>(globalData, unlinkedCode)); return unlinkedCode; } @@ -133,6 +126,7 @@ UnlinkedFunctionCodeBlock* CodeCache::generateFunctionCodeBlock(JSGlobalData& gl body->destroyData(); if (error.m_type != ParserError::ErrorNone) return 0; + m_cachedFunctionCode.add(result, Strong<UnlinkedFunctionCodeBlock>(globalData, result)); return result; } @@ -149,9 +143,9 @@ CodeCache::GlobalFunctionKey CodeCache::makeGlobalFunctionKey(const SourceCode& UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, ParserError& error) { GlobalFunctionKey key = makeGlobalFunctionKey(source, name.string()); - GlobalFunctionIndicesMap::iterator result = m_cachedGlobalFunctionIndices.find(key); - if (result != m_cachedGlobalFunctionIndices.end()) - return m_cachedGlobalFunctions[result->value].second.get(); + const Strong<UnlinkedFunctionExecutable>* result = m_cachedGlobalFunctions.find(key); + if (result) + return result->get(); RefPtr<ProgramNode> program = parse<ProgramNode>(&globalData, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); if (!program) { @@ -173,14 +167,13 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlo UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&globalData, source, body); functionExecutable->m_nameValue.set(globalData, functionExecutable, jsString(&globalData, name.string())); - size_t index = m_randomGenerator.getUint32() % kMaxGlobalFunctionEntries; - if (m_cachedGlobalFunctions[index].second) - m_cachedGlobalFunctionIndices.remove(m_cachedGlobalFunctions[index].first); - m_cachedGlobalFunctionIndices.set(key, index); - m_cachedGlobalFunctions[index].second.set(globalData, functionExecutable); - m_cachedGlobalFunctions[index].first = key; - + m_cachedGlobalFunctions.add(key, Strong<UnlinkedFunctionExecutable>(globalData, functionExecutable)); return functionExecutable; } +void CodeCache::usedFunctionCode(JSGlobalData& globalData, UnlinkedFunctionCodeBlock* codeBlock) +{ + m_cachedFunctionCode.add(codeBlock, Strong<UnlinkedFunctionCodeBlock>(globalData, codeBlock)); +} + } diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h index 4d4617189..740aaa6df 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.h +++ b/Source/JavaScriptCore/runtime/CodeCache.h @@ -34,6 +34,7 @@ #include <wtf/FixedArray.h> #include <wtf/Forward.h> #include <wtf/PassOwnPtr.h> +#include <wtf/RandomNumber.h> #include <wtf/text/WTFString.h> namespace JSC { @@ -51,6 +52,41 @@ struct ParserError; class SourceCode; class SourceProvider; +template <typename KeyType, typename EntryType, int CacheSize> class Thingy { + typedef typename HashMap<KeyType, unsigned>::iterator iterator; +public: + Thingy() + : m_randomGenerator((static_cast<uint32_t>(randomNumber() * UINT32_MAX))) + { + } + const EntryType* find(const KeyType& key) + { + iterator result = m_map.find(key); + if (result == m_map.end()) + return 0; + return &m_data[result->value].second; + } + void add(const KeyType& key, const EntryType& value) + { + iterator result = m_map.find(key); + if (result != m_map.end()) { + m_data[result->value].second = value; + return; + } + size_t newIndex = m_randomGenerator.getUint32() % CacheSize; + if (m_data[newIndex].second) + m_map.remove(m_data[newIndex].first); + m_map.add(key, newIndex); + m_data[newIndex].first = key; + m_data[newIndex].second = value; + ASSERT(m_map.size() <= CacheSize); + } +private: + HashMap<KeyType, unsigned> m_map; + FixedArray<std::pair<KeyType, EntryType>, CacheSize> m_data; + WeakRandom m_randomGenerator; +}; + class CodeCache { public: static PassOwnPtr<CodeCache> create() { return adoptPtr(new CodeCache); } @@ -59,13 +95,12 @@ public: UnlinkedEvalCodeBlock* getEvalCodeBlock(JSGlobalData&, EvalExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); UnlinkedFunctionCodeBlock* getFunctionCodeBlock(JSGlobalData&, UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&); UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(JSGlobalData&, const Identifier&, const SourceCode&, ParserError&); + void usedFunctionCode(JSGlobalData&, UnlinkedFunctionCodeBlock*); ~CodeCache(); enum CodeType { EvalType, ProgramType, FunctionType }; typedef std::pair<String, unsigned> CodeBlockKey; - typedef HashMap<CodeBlockKey, unsigned> CodeBlockIndicesMap; typedef std::pair<String, String> GlobalFunctionKey; - typedef HashMap<GlobalFunctionKey, unsigned> GlobalFunctionIndicesMap; private: CodeCache(); @@ -74,18 +109,17 @@ private: template <class UnlinkedCodeBlockType, class ExecutableType> inline UnlinkedCodeBlockType* getCodeBlock(JSGlobalData&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); CodeBlockKey makeCodeBlockKey(const SourceCode&, CodeType, JSParserStrictness); - CodeBlockIndicesMap m_cachedCodeBlockIndices; GlobalFunctionKey makeGlobalFunctionKey(const SourceCode&, const String&); - GlobalFunctionIndicesMap m_cachedGlobalFunctionIndices; enum { kMaxCodeBlockEntries = 1024, - kMaxGlobalFunctionEntries = 1024 + kMaxGlobalFunctionEntries = 1024, + kMaxFunctionCodeBlocks = 1024 }; - FixedArray<std::pair<CodeBlockKey, Strong<UnlinkedCodeBlock> >, kMaxCodeBlockEntries> m_cachedCodeBlocks; - FixedArray<std::pair<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable> >, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions; - WeakRandom m_randomGenerator; + Thingy<CodeBlockKey, Strong<UnlinkedCodeBlock>, kMaxCodeBlockEntries> m_cachedCodeBlocks; + Thingy<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable>, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions; + Thingy<UnlinkedFunctionCodeBlock*, Strong<UnlinkedFunctionCodeBlock>, kMaxFunctionCodeBlocks> m_cachedFunctionCode; }; } diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 20a2e2acb..49a0e256d 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -620,18 +620,17 @@ void FunctionExecutable::clearCodeIfNotCompiling() clearCode(); } -void FunctionExecutable::clearUnlinkedCodeIfNotCompiling() +void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling() { if (isCompiling()) return; - m_unlinkedExecutable->clearCode(); + m_unlinkedExecutable->clearCodeForRecompilation(); } void FunctionExecutable::clearCode() { m_codeBlockForCall.clear(); m_codeBlockForConstruct.clear(); - m_unlinkedExecutable->clearCode(); Base::clearCode(); } diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index 74b4add75..98471b85b 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -704,7 +704,7 @@ namespace JSC { SharedSymbolTable* symbolTable(CodeSpecializationKind kind) const { return m_unlinkedExecutable->symbolTable(kind); } void clearCodeIfNotCompiling(); - void clearUnlinkedCodeIfNotCompiling(); + void clearUnlinkedCodeForRecompilationIfNotCompiling(); static void visitChildren(JSCell*, SlotVisitor&); static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp index a4b2202c1..8e4390b1b 100644 --- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -186,7 +186,7 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec) // Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order. size_t numBoundArgs = exec->argumentCount() > 1 ? exec->argumentCount() - 1 : 0; - JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructure(), numBoundArgs); + JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), numBoundArgs); if (!boundArgs) return JSValue::encode(throwOutOfMemoryError(exec)); diff --git a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h b/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h index 22785ce24..cfad1c8c2 100644 --- a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h +++ b/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h @@ -23,8 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef IndexingHeaderInlineMethods_h -#define IndexingHeaderInlineMethods_h +#ifndef IndexingHeaderInlines_h +#define IndexingHeaderInlines_h #include "ArrayStorage.h" #include "IndexingHeader.h" @@ -43,6 +43,9 @@ inline size_t IndexingHeader::preCapacity(Structure* structure) inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure) { switch (structure->indexingType()) { + case ALL_UNDECIDED_INDEXING_TYPES: + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return vectorLength() * sizeof(EncodedJSValue); @@ -57,5 +60,5 @@ inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure) } // namespace JSC -#endif // IndexingHeaderInlineMethods_h +#endif // IndexingHeaderInlines_h diff --git a/Source/JavaScriptCore/runtime/IndexingType.cpp b/Source/JavaScriptCore/runtime/IndexingType.cpp index 7261847a2..dc2733ad1 100644 --- a/Source/JavaScriptCore/runtime/IndexingType.cpp +++ b/Source/JavaScriptCore/runtime/IndexingType.cpp @@ -31,6 +31,46 @@ namespace JSC { +IndexingType leastUpperBoundOfIndexingTypes(IndexingType a, IndexingType b) +{ + // It doesn't make sense to LUB something that is an array with something that isn't. + ASSERT((a & IsArray) == (b & IsArray)); + + // Boy, this sure is easy right now. + return std::max(a, b); +} + +IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType indexingType, SpeculatedType type) +{ + if (!type) + return indexingType; + switch (indexingType) { + case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: + case ALL_INT32_INDEXING_TYPES: + if (isInt32Speculation(type)) + return (indexingType & ~IndexingShapeMask) | Int32Shape; + if (isNumberSpeculation(type)) + return (indexingType & ~IndexingShapeMask) | DoubleShape; + return (indexingType & ~IndexingShapeMask) | ContiguousShape; + case ALL_DOUBLE_INDEXING_TYPES: + if (isNumberSpeculation(type)) + return indexingType; + return (indexingType & ~IndexingShapeMask) | ContiguousShape; + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return indexingType; + default: + CRASH(); + return 0; + } +} + +IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType indexingType, JSValue value) +{ + return leastUpperBoundOfIndexingTypeAndType(indexingType, speculationFromValue(value)); +} + const char* indexingTypeToString(IndexingType indexingType) { static char result[128]; @@ -39,6 +79,12 @@ const char* indexingTypeToString(IndexingType indexingType) case NonArray: basicName = "NonArray"; break; + case NonArrayWithInt32: + basicName = "NonArrayWithInt32"; + break; + case NonArrayWithDouble: + basicName = "NonArrayWithDouble"; + break; case NonArrayWithContiguous: basicName = "NonArrayWithContiguous"; break; @@ -51,6 +97,15 @@ const char* indexingTypeToString(IndexingType indexingType) case ArrayClass: basicName = "ArrayClass"; break; + case ArrayWithUndecided: + basicName = "ArrayWithUndecided"; + break; + case ArrayWithInt32: + basicName = "ArrayWithInt32"; + break; + case ArrayWithDouble: + basicName = "ArrayWithDouble"; + break; case ArrayWithContiguous: basicName = "ArrayWithContiguous"; break; diff --git a/Source/JavaScriptCore/runtime/IndexingType.h b/Source/JavaScriptCore/runtime/IndexingType.h index 4bbe3cfa0..ab253be1e 100644 --- a/Source/JavaScriptCore/runtime/IndexingType.h +++ b/Source/JavaScriptCore/runtime/IndexingType.h @@ -26,6 +26,7 @@ #ifndef IndexingType_h #define IndexingType_h +#include "SpeculatedType.h" #include <wtf/StdLibExtras.h> namespace JSC { @@ -37,21 +38,32 @@ static const IndexingType IsArray = 1; // The shape of the indexed property storage. static const IndexingType IndexingShapeMask = 30; -static const IndexingType NoIndexingShape = 0; +static const IndexingType NoIndexingShape = 0; +static const IndexingType UndecidedShape = 2; // Only useful for arrays. +static const IndexingType Int32Shape = 20; +static const IndexingType DoubleShape = 22; static const IndexingType ContiguousShape = 26; static const IndexingType ArrayStorageShape = 28; static const IndexingType SlowPutArrayStorageShape = 30; +static const IndexingType IndexingShapeShift = 1; +static const IndexingType NumberOfIndexingShapes = 16; + // Additional flags for tracking the history of the type. These are usually // masked off unless you ask for them directly. static const IndexingType MayHaveIndexedAccessors = 32; // List of acceptable array types. static const IndexingType NonArray = 0; +static const IndexingType NonArrayWithInt32 = Int32Shape; +static const IndexingType NonArrayWithDouble = DoubleShape; static const IndexingType NonArrayWithContiguous = ContiguousShape; static const IndexingType NonArrayWithArrayStorage = ArrayStorageShape; static const IndexingType NonArrayWithSlowPutArrayStorage = SlowPutArrayStorageShape; static const IndexingType ArrayClass = IsArray; // I'd want to call this "Array" but this would lead to disastrous namespace pollution. +static const IndexingType ArrayWithUndecided = IsArray | UndecidedShape; +static const IndexingType ArrayWithInt32 = IsArray | Int32Shape; +static const IndexingType ArrayWithDouble = IsArray | DoubleShape; static const IndexingType ArrayWithContiguous = IsArray | ContiguousShape; static const IndexingType ArrayWithArrayStorage = IsArray | ArrayStorageShape; static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArrayStorageShape; @@ -60,6 +72,17 @@ static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArr NonArray: \ case ArrayClass +#define ALL_UNDECIDED_INDEXING_TYPES \ + ArrayWithUndecided + +#define ALL_INT32_INDEXING_TYPES \ + NonArrayWithInt32: \ + case ArrayWithInt32 + +#define ALL_DOUBLE_INDEXING_TYPES \ + NonArrayWithDouble: \ + case ArrayWithDouble + #define ALL_CONTIGUOUS_INDEXING_TYPES \ NonArrayWithContiguous: \ case ArrayWithContiguous @@ -83,6 +106,21 @@ static inline bool hasIndexingHeader(IndexingType type) return hasIndexedProperties(type); } +static inline bool hasUndecided(IndexingType indexingType) +{ + return (indexingType & IndexingShapeMask) == UndecidedShape; +} + +static inline bool hasInt32(IndexingType indexingType) +{ + return (indexingType & IndexingShapeMask) == Int32Shape; +} + +static inline bool hasDouble(IndexingType indexingType) +{ + return (indexingType & IndexingShapeMask) == DoubleShape; +} + static inline bool hasContiguous(IndexingType indexingType) { return (indexingType & IndexingShapeMask) == ContiguousShape; @@ -105,6 +143,12 @@ static inline bool shouldUseSlowPut(IndexingType indexingType) return (indexingType & IndexingShapeMask) == SlowPutArrayStorageShape; } +// Return an indexing type that can handle all of the elements of both indexing types. +IndexingType leastUpperBoundOfIndexingTypes(IndexingType, IndexingType); + +IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType, SpeculatedType); +IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType, JSValue); + const char* indexingTypeToString(IndexingType); // Mask of all possible types. diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h index fc6336463..b8f5621af 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.h +++ b/Source/JavaScriptCore/runtime/JSActivation.h @@ -30,7 +30,7 @@ #define JSActivation_h #include "CodeBlock.h" -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "JSVariableObject.h" #include "Nodes.h" #include "SymbolTable.h" diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index d1ece1a36..4ba5cc2bd 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -24,14 +24,14 @@ #include "JSArray.h" #include "ArrayPrototype.h" -#include "ButterflyInlineMethods.h" -#include "CopiedSpace.h" -#include "CopiedSpaceInlineMethods.h" +#include "ButterflyInlines.h" #include "CachedCall.h" +#include "CopiedSpace.h" +#include "CopiedSpaceInlines.h" #include "Error.h" #include "Executable.h" #include "GetterSetter.h" -#include "IndexingHeaderInlineMethods.h" +#include "IndexingHeaderInlines.h" #include "PropertyNameArray.h" #include "Reject.h" #include <wtf/AVLTree.h> @@ -410,25 +410,33 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException exec, newLength, throwException, convertContiguousToArrayStorage(exec->globalData())); } - createInitialContiguous(exec->globalData(), newLength); + createInitialUndecided(exec->globalData(), newLength); return true; + case ArrayWithUndecided: + case ArrayWithInt32: + case ArrayWithDouble: case ArrayWithContiguous: if (newLength == m_butterfly->publicLength()) return true; if (newLength >= MAX_ARRAY_INDEX // This case ensures that we can do fast push. || (newLength >= MIN_SPARSE_ARRAY_INDEX - && !isDenseEnoughForVector(newLength, countElementsInContiguous(m_butterfly)))) { + && !isDenseEnoughForVector(newLength, countElements()))) { return setLengthWithArrayStorage( exec, newLength, throwException, - convertContiguousToArrayStorage(exec->globalData())); + ensureArrayStorage(exec->globalData())); } if (newLength > m_butterfly->publicLength()) { - ensureContiguousLength(exec->globalData(), newLength); + ensureLength(exec->globalData(), newLength); return true; } - for (unsigned i = m_butterfly->publicLength(); i-- > newLength;) - m_butterfly->contiguous()[i].clear(); + if (structure()->indexingType() == ArrayWithDouble) { + for (unsigned i = m_butterfly->publicLength(); i-- > newLength;) + m_butterfly->contiguousDouble()[i] = QNaN; + } else { + for (unsigned i = m_butterfly->publicLength(); i-- > newLength;) + m_butterfly->contiguous()[i].clear(); + } m_butterfly->setPublicLength(newLength); return true; @@ -448,6 +456,13 @@ JSValue JSArray::pop(ExecState* exec) case ArrayClass: return jsUndefined(); + case ArrayWithUndecided: + if (!m_butterfly->publicLength()) + return jsUndefined(); + // We have nothing but holes. So, drop down to the slow version. + break; + + case ArrayWithInt32: case ArrayWithContiguous: { unsigned length = m_butterfly->publicLength(); @@ -464,6 +479,22 @@ JSValue JSArray::pop(ExecState* exec) break; } + case ArrayWithDouble: { + unsigned length = m_butterfly->publicLength(); + + if (!length--) + return jsUndefined(); + + ASSERT(length < m_butterfly->vectorLength()); + double value = m_butterfly->contiguousDouble()[length]; + if (value == value) { + m_butterfly->contiguousDouble()[length] = QNaN; + m_butterfly->setPublicLength(length); + return JSValue(JSValue::EncodeAsDouble, value); + } + break; + } + case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = m_butterfly->arrayStorage(); @@ -518,10 +549,42 @@ void JSArray::push(ExecState* exec, JSValue value) { switch (structure()->indexingType()) { case ArrayClass: { - putByIndexBeyondVectorLengthWithArrayStorage(exec, 0, value, true, createInitialArrayStorage(exec->globalData())); - break; + createInitialUndecided(exec->globalData(), 0); + // Fall through. + } + + case ArrayWithUndecided: { + convertUndecidedForValue(exec->globalData(), value); + push(exec, value); + return; } + case ArrayWithInt32: { + if (!value.isInt32()) { + convertInt32ForValue(exec->globalData(), value); + push(exec, value); + return; + } + + unsigned length = m_butterfly->publicLength(); + ASSERT(length <= m_butterfly->vectorLength()); + if (length < m_butterfly->vectorLength()) { + m_butterfly->contiguousInt32()[length].setWithoutWriteBarrier(value); + m_butterfly->setPublicLength(length + 1); + return; + } + + if (length > MAX_ARRAY_INDEX) { + methodTable()->putByIndex(this, exec, length, value, true); + if (!exec->hadException()) + throwError(exec, createRangeError(exec, "Invalid array length")); + return; + } + + putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, length, value); + return; + } + case ArrayWithContiguous: { unsigned length = m_butterfly->publicLength(); ASSERT(length <= m_butterfly->vectorLength()); @@ -538,10 +601,42 @@ void JSArray::push(ExecState* exec, JSValue value) return; } - putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, length, value); + putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, length, value); return; } + case ArrayWithDouble: { + if (!value.isNumber()) { + convertDoubleToContiguous(exec->globalData()); + push(exec, value); + return; + } + double valueAsDouble = value.asNumber(); + if (valueAsDouble != valueAsDouble) { + convertDoubleToContiguous(exec->globalData()); + push(exec, value); + return; + } + + unsigned length = m_butterfly->publicLength(); + ASSERT(length <= m_butterfly->vectorLength()); + if (length < m_butterfly->vectorLength()) { + m_butterfly->contiguousDouble()[length] = valueAsDouble; + m_butterfly->setPublicLength(length + 1); + return; + } + + if (length > MAX_ARRAY_INDEX) { + methodTable()->putByIndex(this, exec, length, value, true); + if (!exec->hadException()) + throwError(exec, createRangeError(exec, "Invalid array length")); + return; + } + + putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, length, value); + break; + } + case ArrayWithSlowPutArrayStorage: { unsigned oldLength = length(); if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true)) { @@ -647,6 +742,11 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex case ArrayClass: return true; + case ArrayWithUndecided: + // Don't handle this because it's confusing and it shouldn't come up. + return false; + + case ArrayWithInt32: case ArrayWithContiguous: { unsigned oldLength = m_butterfly->publicLength(); ASSERT(count <= oldLength); @@ -654,7 +754,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex // We may have to walk the entire array to do the shift. We're willing to do // so only if it's not horribly slow. if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX) - return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData())); + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); unsigned end = oldLength - count; for (unsigned i = startIndex; i < end; ++i) { @@ -668,7 +768,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex // about holes (at least for now), but it can detect them quickly. So // we convert to array storage and then allow the array storage path to // figure it out. - return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData())); + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); } // No need for a barrier since we're just moving data around in the same vector. // This is in line with our standing assumption that we won't have a deletion @@ -682,6 +782,41 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex return true; } + case ArrayWithDouble: { + unsigned oldLength = m_butterfly->publicLength(); + ASSERT(count <= oldLength); + + // We may have to walk the entire array to do the shift. We're willing to do + // so only if it's not horribly slow. + if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX) + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); + + unsigned end = oldLength - count; + for (unsigned i = startIndex; i < end; ++i) { + // Storing to a hole is fine since we're still having a good time. But reading + // from a hole is totally not fine, since we might have to read from the proto + // chain. + double v = m_butterfly->contiguousDouble()[i + count]; + if (UNLIKELY(v != v)) { + // The purpose of this path is to ensure that we don't make the same + // mistake in the future: shiftCountWithArrayStorage() can't do anything + // about holes (at least for now), but it can detect them quickly. So + // we convert to array storage and then allow the array storage path to + // figure it out. + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); + } + // No need for a barrier since we're just moving data around in the same vector. + // This is in line with our standing assumption that we won't have a deletion + // barrier. + m_butterfly->contiguousDouble()[i] = v; + } + for (unsigned i = end; i < oldLength; ++i) + m_butterfly->contiguousDouble()[i] = QNaN; + + m_butterfly->setPublicLength(oldLength - count); + return true; + } + case ArrayWithArrayStorage: case ArrayWithSlowPutArrayStorage: return shiftCountWithArrayStorage(startIndex, count, arrayStorage()); @@ -740,23 +875,25 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd { switch (structure()->indexingType()) { case ArrayClass: + case ArrayWithUndecided: // We could handle this. But it shouldn't ever come up, so we won't. return false; - + + case ArrayWithInt32: case ArrayWithContiguous: { unsigned oldLength = m_butterfly->publicLength(); // We may have to walk the entire array to do the unshift. We're willing to do so // only if it's not horribly slow. if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX) - return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData())); + return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); - ensureContiguousLength(exec->globalData(), oldLength + count); + ensureLength(exec->globalData(), oldLength + count); for (unsigned i = oldLength; i-- > startIndex;) { JSValue v = m_butterfly->contiguous()[i].get(); if (UNLIKELY(!v)) - return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData())); + return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v); } @@ -768,6 +905,31 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd return true; } + case ArrayWithDouble: { + unsigned oldLength = m_butterfly->publicLength(); + + // We may have to walk the entire array to do the unshift. We're willing to do so + // only if it's not horribly slow. + if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX) + return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); + + ensureLength(exec->globalData(), oldLength + count); + + for (unsigned i = oldLength; i-- > startIndex;) { + double v = m_butterfly->contiguousDouble()[i]; + if (UNLIKELY(v != v)) + return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); + m_butterfly->contiguousDouble()[i + count] = v; + } + + // NOTE: we're leaving being garbage in the part of the array that we shifted out + // of. This is fine because the caller is required to store over that area, and + // in contiguous mode storing into a hole is guaranteed to behave exactly the same + // as storing over an existing element. + + return true; + } + case ArrayWithArrayStorage: case ArrayWithSlowPutArrayStorage: return unshiftCountWithArrayStorage(exec, startIndex, count, arrayStorage()); @@ -778,6 +940,20 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd } } +static int compareNumbersForQSortWithInt32(const void* a, const void* b) +{ + int32_t ia = static_cast<const JSValue*>(a)->asInt32(); + int32_t ib = static_cast<const JSValue*>(b)->asInt32(); + return ia - ib; +} + +static int compareNumbersForQSortWithDouble(const void* a, const void* b) +{ + double da = *static_cast<const double*>(a); + double db = *static_cast<const double*>(b); + return (da > db) - (da < db); +} + static int compareNumbersForQSort(const void* a, const void* b) { double da = static_cast<const JSValue*>(a)->asNumber(); @@ -795,7 +971,7 @@ static int compareByStringPairForQSort(const void* a, const void* b) template<IndexingType indexingType> void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) { - ASSERT(indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage); + ASSERT(indexingType == ArrayWithInt32 || indexingType == ArrayWithDouble || indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage); unsigned lengthNotIncludingUndefined; unsigned newRelevantLength; @@ -814,11 +990,19 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy return; bool allValuesAreNumbers = true; - for (size_t i = 0; i < newRelevantLength; ++i) { - if (!data[i].isNumber()) { - allValuesAreNumbers = false; - break; + switch (indexingType) { + case ArrayWithInt32: + case ArrayWithDouble: + break; + + default: + for (size_t i = 0; i < newRelevantLength; ++i) { + if (!data[i].isNumber()) { + allValuesAreNumbers = false; + break; + } } + break; } if (!allValuesAreNumbers) @@ -827,7 +1011,23 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy // For numeric comparison, which is fast, qsort is faster than mergesort. We // also don't require mergesort's stability, since there's no user visible // side-effect from swapping the order of equal primitive values. - qsort(data, newRelevantLength, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort); + int (*compare)(const void*, const void*); + switch (indexingType) { + case ArrayWithInt32: + compare = compareNumbersForQSortWithInt32; + break; + + case ArrayWithDouble: + compare = compareNumbersForQSortWithDouble; + ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(double)); + break; + + default: + compare = compareNumbersForQSort; + break; + } + + qsort(data, newRelevantLength, sizeof(WriteBarrier<Unknown>), compare); return; } @@ -839,6 +1039,14 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal case ArrayClass: return; + case ArrayWithInt32: + sortNumericVector<ArrayWithInt32>(exec, compareFunction, callType, callData); + break; + + case ArrayWithDouble: + sortNumericVector<ArrayWithDouble>(exec, compareFunction, callType, callData); + break; + case ArrayWithContiguous: sortNumericVector<ArrayWithContiguous>(exec, compareFunction, callType, callData); return; @@ -854,7 +1062,7 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal } template<IndexingType indexingType> -void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin, unsigned relevantLength) +void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevantLength) { if (!relevantLength) return; @@ -875,11 +1083,31 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin, Heap::heap(this)->pushTempSortVector(&values); bool isSortingPrimitiveValues = true; - for (size_t i = 0; i < relevantLength; i++) { - JSValue value = begin[i].get(); - ASSERT(!value.isUndefined()); - values[i].first = value; - isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive(); + switch (indexingType) { + case ArrayWithInt32: + for (size_t i = 0; i < relevantLength; i++) { + JSValue value = static_cast<WriteBarrier<Unknown>*>(begin)[i].get(); + ASSERT(value.isInt32()); + values[i].first = value; + } + break; + + case ArrayWithDouble: + for (size_t i = 0; i < relevantLength; i++) { + double value = static_cast<double*>(begin)[i]; + ASSERT(value == value); + values[i].first = JSValue(JSValue::EncodeAsDouble, value); + } + break; + + default: + for (size_t i = 0; i < relevantLength; i++) { + JSValue value = static_cast<WriteBarrier<Unknown>*>(begin)[i].get(); + ASSERT(!value.isUndefined()); + values[i].first = value; + isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive(); + } + break; } // FIXME: The following loop continues to call toString on subsequent values even after @@ -910,8 +1138,10 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin, // If the toString function changed the length of the array or vector storage, // increase the length to handle the orignal number of actual values. switch (indexingType) { + case ArrayWithInt32: + case ArrayWithDouble: case ArrayWithContiguous: - ensureContiguousLength(globalData, relevantLength); + ensureLength(globalData, relevantLength); break; case ArrayWithArrayStorage: @@ -927,8 +1157,12 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin, CRASH(); } - for (size_t i = 0; i < relevantLength; i++) - begin[i].set(globalData, this, values[i].first); + for (size_t i = 0; i < relevantLength; i++) { + if (indexingType == ArrayWithDouble) + static_cast<double*>(begin)[i] = values[i].first.asNumber(); + else + static_cast<WriteBarrier<Unknown>*>(begin)[i].set(globalData, this, values[i].first); + } Heap::heap(this)->popTempSortVector(&values); } @@ -939,8 +1173,31 @@ void JSArray::sort(ExecState* exec) switch (structure()->indexingType()) { case ArrayClass: + case ArrayWithUndecided: return; + case ArrayWithInt32: { + unsigned lengthNotIncludingUndefined; + unsigned newRelevantLength; + compactForSorting<ArrayWithInt32>( + lengthNotIncludingUndefined, newRelevantLength); + + sortCompactedVector<ArrayWithInt32>( + exec, m_butterfly->contiguousInt32(), lengthNotIncludingUndefined); + return; + } + + case ArrayWithDouble: { + unsigned lengthNotIncludingUndefined; + unsigned newRelevantLength; + compactForSorting<ArrayWithDouble>( + lengthNotIncludingUndefined, newRelevantLength); + + sortCompactedVector<ArrayWithDouble>( + exec, m_butterfly->contiguousDouble(), lengthNotIncludingUndefined); + return; + } + case ArrayWithContiguous: { unsigned lengthNotIncludingUndefined; unsigned newRelevantLength; @@ -1087,12 +1344,12 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call unsigned numDefined = 0; unsigned numUndefined = 0; - + // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree. for (; numDefined < usedVectorLength; ++numDefined) { if (numDefined > m_butterfly->vectorLength()) break; - JSValue v = currentIndexingData()[numDefined].get(); + JSValue v = getHolyIndexQuickly(numDefined); if (!v || v.isUndefined()) break; tree.abstractor().m_nodes[numDefined].value = v; @@ -1101,7 +1358,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call for (unsigned i = numDefined; i < usedVectorLength; ++i) { if (i > m_butterfly->vectorLength()) break; - JSValue v = currentIndexingData()[i].get(); + JSValue v = getHolyIndexQuickly(i); if (v) { if (v.isUndefined()) ++numUndefined; @@ -1112,7 +1369,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call } } } - + unsigned newUsedVectorLength = numDefined + numUndefined; // The array size may have changed. Figure out the new bounds. @@ -1127,16 +1384,31 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call iter.start_iter_least(tree); JSGlobalData& globalData = exec->globalData(); for (unsigned i = 0; i < elementsToExtractThreshold; ++i) { - currentIndexingData()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); + if (structure()->indexingType() == ArrayWithDouble) + butterfly()->contiguousDouble()[i] = tree.abstractor().m_nodes[*iter].value.asNumber(); + else + currentIndexingData()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); ++iter; } // Put undefined values back in. - for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i) - currentIndexingData()[i].setUndefined(); + switch (structure()->indexingType()) { + case ArrayWithInt32: + case ArrayWithDouble: + ASSERT(elementsToExtractThreshold == undefinedElementsThreshold); + break; + + default: + for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i) + currentIndexingData()[i].setUndefined(); + } // Ensure that unused values in the vector are zeroed out. - for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) - currentIndexingData()[i].clear(); + for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) { + if (structure()->indexingType() == ArrayWithDouble) + butterfly()->contiguousDouble()[i] = QNaN; + else + currentIndexingData()[i].clear(); + } if (hasArrayStorage(structure()->indexingType())) arrayStorage()->m_numValuesInVector = newUsedVectorLength; @@ -1148,8 +1420,17 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, switch (structure()->indexingType()) { case ArrayClass: + case ArrayWithUndecided: return; + case ArrayWithInt32: + sortVector<ArrayWithInt32>(exec, compareFunction, callType, callData); + return; + + case ArrayWithDouble: + sortVector<ArrayWithDouble>(exec, compareFunction, callType, callData); + return; + case ArrayWithContiguous: sortVector<ArrayWithContiguous>(exec, compareFunction, callType, callData); return; @@ -1173,11 +1454,30 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) case ArrayClass: return; + case ArrayWithUndecided: { + vector = 0; + vectorEnd = 0; + break; + } + + case ArrayWithInt32: case ArrayWithContiguous: { vectorEnd = m_butterfly->publicLength(); vector = m_butterfly->contiguous(); break; } + + case ArrayWithDouble: { + vector = 0; + vectorEnd = 0; + for (; i < m_butterfly->publicLength(); ++i) { + double v = butterfly()->contiguousDouble()[i]; + if (v != v) + break; + args.append(JSValue(JSValue::EncodeAsDouble, v)); + } + break; + } case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = m_butterfly->arrayStorage(); @@ -1216,12 +1516,31 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le case ArrayClass: return; + case ArrayWithUndecided: { + vector = 0; + vectorEnd = 0; + break; + } + + case ArrayWithInt32: case ArrayWithContiguous: { vector = m_butterfly->contiguous(); vectorEnd = m_butterfly->publicLength(); break; } + case ArrayWithDouble: { + vector = 0; + vectorEnd = 0; + for (; i < m_butterfly->publicLength(); ++i) { + double v = m_butterfly->contiguousDouble()[i]; + if (v != v) + break; + callFrame->setArgument(i, JSValue(JSValue::EncodeAsDouble, v)); + } + break; + } + case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = m_butterfly->arrayStorage(); vector = storage->m_vector; @@ -1259,12 +1578,40 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt unsigned numUndefined = 0; for (; numDefined < myRelevantLength; ++numDefined) { + if (indexingType == ArrayWithInt32) { + JSValue v = m_butterfly->contiguousInt32()[numDefined].get(); + if (!v) + break; + ASSERT(v.isInt32()); + continue; + } + if (indexingType == ArrayWithDouble) { + double v = m_butterfly->contiguousDouble()[numDefined]; + if (v != v) + break; + continue; + } JSValue v = indexingData<indexingType>()[numDefined].get(); if (!v || v.isUndefined()) break; } for (unsigned i = numDefined; i < myRelevantLength; ++i) { + if (indexingType == ArrayWithInt32) { + JSValue v = m_butterfly->contiguousInt32()[i].get(); + if (!v) + continue; + ASSERT(v.isInt32()); + m_butterfly->contiguousInt32()[numDefined++].setWithoutWriteBarrier(v); + continue; + } + if (indexingType == ArrayWithDouble) { + double v = m_butterfly->contiguousDouble()[i]; + if (v != v) + continue; + m_butterfly->contiguousDouble()[numDefined++] = v; + continue; + } JSValue v = indexingData<indexingType>()[i].get(); if (v) { if (v.isUndefined()) @@ -1279,10 +1626,23 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt if (hasArrayStorage(indexingType)) ASSERT(!arrayStorage()->m_sparseMap); - for (unsigned i = numDefined; i < newRelevantLength; ++i) - indexingData<indexingType>()[i].setUndefined(); - for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) - indexingData<indexingType>()[i].clear(); + switch (indexingType) { + case ArrayWithInt32: + case ArrayWithDouble: + ASSERT(numDefined == newRelevantLength); + break; + + default: + for (unsigned i = numDefined; i < newRelevantLength; ++i) + indexingData<indexingType>()[i].setUndefined(); + break; + } + for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) { + if (indexingType == ArrayWithDouble) + m_butterfly->contiguousDouble()[i] = QNaN; + else + indexingData<indexingType>()[i].clear(); + } if (hasArrayStorage(indexingType)) arrayStorage()->m_numValuesInVector = newRelevantLength; diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index 1d1e64173..ea1ed9047 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -22,7 +22,7 @@ #define JSArray_h #include "ArrayConventions.h" -#include "ButterflyInlineMethods.h" +#include "ButterflyInlines.h" #include "JSObject.h" namespace JSC { @@ -162,7 +162,7 @@ private: void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&); template<IndexingType indexingType> - void sortCompactedVector(ExecState*, WriteBarrier<Unknown>* begin, unsigned relevantLength); + void sortCompactedVector(ExecState*, void* begin, unsigned relevantLength); template<IndexingType indexingType> void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&); @@ -174,13 +174,14 @@ private: void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength); }; -inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length) +inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length, unsigned& vectorLength) { IndexingHeader header; - header.setVectorLength(std::max(length, BASE_VECTOR_LEN)); + vectorLength = std::max(length, BASE_VECTOR_LEN); + header.setVectorLength(vectorLength); header.setPublicLength(length); Butterfly* result = Butterfly::create( - globalData, 0, 0, true, header, header.vectorLength() * sizeof(EncodedJSValue)); + globalData, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue)); return result; } @@ -200,13 +201,23 @@ Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData&, unsigned inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength) { Butterfly* butterfly; - if (LIKELY(structure->indexingType() == ArrayWithContiguous)) { - butterfly = createContiguousArrayButterfly(globalData, initialLength); + if (LIKELY(!hasArrayStorage(structure->indexingType()))) { + ASSERT( + hasUndecided(structure->indexingType()) + || hasInt32(structure->indexingType()) + || hasDouble(structure->indexingType()) + || hasContiguous(structure->indexingType())); + unsigned vectorLength; + butterfly = createContiguousArrayButterfly(globalData, initialLength, vectorLength); ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX); + if (hasDouble(structure->indexingType())) { + for (unsigned i = 0; i < vectorLength; ++i) + butterfly->contiguousDouble()[i] = QNaN; + } } else { ASSERT( structure->indexingType() == ArrayWithSlowPutArrayStorage - || (initialLength && structure->indexingType() == ArrayWithArrayStorage)); + || structure->indexingType() == ArrayWithArrayStorage); butterfly = createArrayButterfly(globalData, initialLength); } JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); @@ -221,8 +232,13 @@ inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Struct return 0; Butterfly* butterfly; - if (LIKELY(structure->indexingType() == ArrayWithContiguous)) { - + if (LIKELY(!hasArrayStorage(structure->indexingType()))) { + ASSERT( + hasUndecided(structure->indexingType()) + || hasInt32(structure->indexingType()) + || hasDouble(structure->indexingType()) + || hasContiguous(structure->indexingType())); + void* temp; if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp)) return 0; diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index 3b37613d1..df31b8542 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -28,9 +28,9 @@ #include "ConstructData.h" #include "Heap.h" #include "JSLock.h" -#include "JSValueInlineMethods.h" +#include "JSValueInlines.h" #include "SlotVisitor.h" -#include "SlotVisitorInlineMethods.h" +#include "SlotVisitorInlines.h" #include "TypedArrayDescriptor.h" #include "WriteBarrier.h" #include <wtf/Noncopyable.h> diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index c466a2b04..a7c6c8c18 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -230,9 +230,16 @@ void JSGlobalObject::reset(JSValue prototype) m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSDestructibleObject>::createStructure(exec->globalData(), this, m_objectPrototype.get())); m_arrayPrototype.set(exec->globalData(), this, ArrayPrototype::create(exec, this, ArrayPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()))); - m_arrayStructure.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithContiguous)); - m_arrayStructureWithArrayStorage.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage)); - m_arrayStructureForSlowPut.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage)); + + m_originalArrayStructureForIndexingShape[UndecidedShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithUndecided)); + m_originalArrayStructureForIndexingShape[Int32Shape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithInt32)); + m_originalArrayStructureForIndexingShape[DoubleShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithDouble)); + m_originalArrayStructureForIndexingShape[ContiguousShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithContiguous)); + m_originalArrayStructureForIndexingShape[ArrayStorageShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage)); + m_originalArrayStructureForIndexingShape[SlowPutArrayStorageShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage)); + for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) + m_arrayStructureForIndexingShapeDuringAllocation[i] = m_originalArrayStructureForIndexingShape[i]; + m_regExpMatchesArrayStructure.set(exec->globalData(), this, RegExpMatchesArray::createStructure(exec->globalData(), this, m_arrayPrototype.get())); m_stringPrototype.set(exec->globalData(), this, StringPrototype::create(exec, this, StringPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()))); @@ -360,7 +367,9 @@ inline bool hasBrokenIndexing(JSObject* object) { // This will change if we have more indexing types. IndexingType type = object->structure()->indexingType(); - return hasContiguous(type) || hasFastArrayStorage(type); + // This could be made obviously more efficient, but isn't made so right now, because + // we expect this to be an unlikely slow path anyway. + return hasUndecided(type) || hasInt32(type) || hasDouble(type) || hasContiguous(type) || hasFastArrayStorage(type); } void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell) @@ -412,8 +421,8 @@ void JSGlobalObject::haveABadTime(JSGlobalData& globalData) // Make sure that all JSArray allocations that load the appropriate structure from // this object now load a structure that uses SlowPut. - m_arrayStructure.set(globalData, this, m_arrayStructureForSlowPut.get()); - m_arrayStructureWithArrayStorage.set(globalData, this, m_arrayStructureForSlowPut.get()); + for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) + m_arrayStructureForIndexingShapeDuringAllocation[i].set(globalData, this, originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage)); // Make sure that all objects that have indexed storage switch to the slow kind of // indexed storage. @@ -488,9 +497,10 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_activationStructure); visitor.append(&thisObject->m_nameScopeStructure); visitor.append(&thisObject->m_argumentsStructure); - visitor.append(&thisObject->m_arrayStructure); - visitor.append(&thisObject->m_arrayStructureWithArrayStorage); - visitor.append(&thisObject->m_arrayStructureForSlowPut); + for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) + visitor.append(&thisObject->m_originalArrayStructureForIndexingShape[i]); + for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) + visitor.append(&thisObject->m_arrayStructureForIndexingShapeDuringAllocation[i]); visitor.append(&thisObject->m_booleanObjectStructure); visitor.append(&thisObject->m_callbackConstructorStructure); visitor.append(&thisObject->m_callbackFunctionStructure); diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index 3212363ab..121b71b72 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -22,6 +22,7 @@ #ifndef JSGlobalObject_h #define JSGlobalObject_h +#include "ArrayAllocationProfile.h" #include "JSArray.h" #include "JSGlobalData.h" #include "JSSegmentedVariableObject.h" @@ -130,9 +131,12 @@ namespace JSC { WriteBarrier<Structure> m_activationStructure; WriteBarrier<Structure> m_nameScopeStructure; WriteBarrier<Structure> m_argumentsStructure; - WriteBarrier<Structure> m_arrayStructure; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time. - WriteBarrier<Structure> m_arrayStructureWithArrayStorage; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time. - WriteBarrier<Structure> m_arrayStructureForSlowPut; + + // Lists the actual structures used for having these particular indexing shapes. + WriteBarrier<Structure> m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes]; + // Lists the structures we should use during allocation for these particular indexing shapes. + WriteBarrier<Structure> m_arrayStructureForIndexingShapeDuringAllocation[NumberOfIndexingShapes]; + WriteBarrier<Structure> m_booleanObjectStructure; WriteBarrier<Structure> m_callbackConstructorStructure; WriteBarrier<Structure> m_callbackFunctionStructure; @@ -275,14 +279,26 @@ namespace JSC { Structure* activationStructure() const { return m_activationStructure.get(); } Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); } Structure* argumentsStructure() const { return m_argumentsStructure.get(); } - Structure* arrayStructure() const { return m_arrayStructure.get(); } - Structure* arrayStructureWithArrayStorage() const { return m_arrayStructureWithArrayStorage.get(); } - void* addressOfArrayStructure() { return &m_arrayStructure; } - void* addressOfArrayStructureWithArrayStorage() { return &m_arrayStructureWithArrayStorage; } + Structure* originalArrayStructureForIndexingType(IndexingType indexingType) const + { + ASSERT(indexingType & IsArray); + return m_originalArrayStructureForIndexingShape[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get(); + } + Structure* arrayStructureForIndexingTypeDuringAllocation(IndexingType indexingType) const + { + ASSERT(indexingType & IsArray); + return m_arrayStructureForIndexingShapeDuringAllocation[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get(); + } + Structure* arrayStructureForProfileDuringAllocation(ArrayAllocationProfile* profile) const + { + return arrayStructureForIndexingTypeDuringAllocation(ArrayAllocationProfile::selectIndexingTypeFor(profile)); + } + bool isOriginalArrayStructure(Structure* structure) { - return structure == m_arrayStructure.get() || structure == m_arrayStructureWithArrayStorage.get(); + return originalArrayStructureForIndexingType(structure->indexingType() | IsArray) == structure; } + Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); } Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); } Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); } @@ -497,34 +513,34 @@ namespace JSC { return constructEmptyObject(exec, exec->lexicalGlobalObject()); } - inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength = 0) + inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0) { - return JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureWithArrayStorage() : globalObject->arrayStructure(), initialLength); + return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength)); } - inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength = 0) + inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0) { - return constructEmptyArray(exec, exec->lexicalGlobalObject(), initialLength); + return constructEmptyArray(exec, profile, exec->lexicalGlobalObject(), initialLength); } - inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const ArgList& values) + inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList& values) { - return constructArray(exec, globalObject->arrayStructure(), values); + return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values)); } - inline JSArray* constructArray(ExecState* exec, const ArgList& values) + inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList& values) { - return constructArray(exec, exec->lexicalGlobalObject(), values); + return constructArray(exec, profile, exec->lexicalGlobalObject(), values); } - inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const JSValue* values, unsigned length) + inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length) { - return constructArray(exec, globalObject->arrayStructure(), values, length); + return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values, length)); } - inline JSArray* constructArray(ExecState* exec, const JSValue* values, unsigned length) + inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length) { - return constructArray(exec, exec->lexicalGlobalObject(), values, length); + return constructArray(exec, profile, exec->lexicalGlobalObject(), values, length); } class DynamicGlobalObjectScope { diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index 6a3fb84e4..a67896b1a 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -24,14 +24,14 @@ #include "config.h" #include "JSObject.h" -#include "ButterflyInlineMethods.h" -#include "CopiedSpaceInlineMethods.h" +#include "ButterflyInlines.h" +#include "CopiedSpaceInlines.h" #include "CopyVisitor.h" -#include "CopyVisitorInlineMethods.h" +#include "CopyVisitorInlines.h" #include "DatePrototype.h" #include "ErrorConstructor.h" #include "GetterSetter.h" -#include "IndexingHeaderInlineMethods.h" +#include "IndexingHeaderInlines.h" #include "JSFunction.h" #include "JSGlobalObject.h" #include "Lookup.h" @@ -42,7 +42,7 @@ #include "PropertyDescriptor.h" #include "PropertyNameArray.h" #include "Reject.h" -#include "SlotVisitorInlineMethods.h" +#include "SlotVisitorInlines.h" #include <math.h> #include <wtf/Assertions.h> @@ -129,7 +129,16 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt size_t count; switch (structure->indexingType()) { - case ALL_CONTIGUOUS_INDEXING_TYPES: { + case ALL_UNDECIDED_INDEXING_TYPES: { + currentTarget = 0; + currentSource = 0; + count = 0; + break; + } + + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: { currentTarget = newButterfly->contiguous(); currentSource = butterfly->contiguous(); ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength()); @@ -152,8 +161,7 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt break; } - while (count--) - (currentTarget++)->setWithoutWriteBarrier((currentSource++)->get()); + memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue)); } m_butterfly = newButterfly; @@ -272,8 +280,10 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned switch (thisObject->structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: break; + case ALL_INT32_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: { Butterfly* butterfly = thisObject->m_butterfly; if (i >= butterfly->vectorLength()) @@ -288,6 +298,20 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned return false; } + case ALL_DOUBLE_INDEXING_TYPES: { + Butterfly* butterfly = thisObject->m_butterfly; + if (i >= butterfly->vectorLength()) + return false; + + double value = butterfly->contiguousDouble()[i]; + if (value == value) { + slot.setValue(JSValue(JSValue::EncodeAsDouble, value)); + return true; + } + + return false; + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = thisObject->m_butterfly->arrayStorage(); if (i >= storage->length()) @@ -405,6 +429,22 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, case ALL_BLANK_INDEXING_TYPES: break; + case ALL_UNDECIDED_INDEXING_TYPES: { + thisObject->convertUndecidedForValue(exec->globalData(), value); + // Reloop. + putByIndex(cell, exec, propertyName, value, shouldThrow); + return; + } + + case ALL_INT32_INDEXING_TYPES: { + if (!value.isInt32()) { + thisObject->convertInt32ForValue(exec->globalData(), value); + putByIndex(cell, exec, propertyName, value, shouldThrow); + return; + } + // Fall through. + } + case ALL_CONTIGUOUS_INDEXING_TYPES: { Butterfly* butterfly = thisObject->m_butterfly; if (propertyName >= butterfly->vectorLength()) @@ -415,6 +455,29 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, return; } + case ALL_DOUBLE_INDEXING_TYPES: { + if (!value.isNumber()) { + thisObject->convertDoubleToContiguous(exec->globalData()); + // Reloop. + putByIndex(cell, exec, propertyName, value, shouldThrow); + return; + } + double valueAsDouble = value.asNumber(); + if (valueAsDouble != valueAsDouble) { + thisObject->convertDoubleToContiguous(exec->globalData()); + // Reloop. + putByIndex(cell, exec, propertyName, value, shouldThrow); + return; + } + Butterfly* butterfly = thisObject->m_butterfly; + if (propertyName >= butterfly->vectorLength()) + break; + butterfly->contiguousDouble()[propertyName] = valueAsDouble; + if (propertyName >= butterfly->publicLength()) + butterfly->setPublicLength(propertyName + 1); + return; + } + case NonArrayWithArrayStorage: case ArrayWithArrayStorage: { ArrayStorage* storage = thisObject->m_butterfly->arrayStorage(); @@ -507,10 +570,13 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists void JSObject::enterDictionaryIndexingMode(JSGlobalData& globalData) { switch (structure()->indexingType()) { + case ALL_UNDECIDED_INDEXING_TYPES: + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: // NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize // this case if we ever cared. - enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData)); + enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, ensureArrayStorageSlow(globalData)); break; case ALL_ARRAY_STORAGE_INDEXING_TYPES: enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage()); @@ -534,7 +600,7 @@ void JSObject::notifyPresenceOfIndexedAccessors(JSGlobalData& globalData) globalObject()->haveABadTime(globalData); } -WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length) +Butterfly* JSObject::createInitialIndexedStorage(JSGlobalData& globalData, unsigned length, size_t elementSize) { ASSERT(length < MAX_ARRAY_INDEX); IndexingType oldType = structure()->indexingType(); @@ -544,9 +610,41 @@ WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalDat unsigned vectorLength = std::max(length, BASE_VECTOR_LEN); Butterfly* newButterfly = m_butterfly->growArrayRight( globalData, structure(), structure()->outOfLineCapacity(), false, 0, - sizeof(EncodedJSValue) * vectorLength); + elementSize * vectorLength); newButterfly->setPublicLength(length); newButterfly->setVectorLength(vectorLength); + return newButterfly; +} + +Butterfly* JSObject::createInitialUndecided(JSGlobalData& globalData, unsigned length) +{ + Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue)); + Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateUndecided); + setButterfly(globalData, newButterfly, newStructure); + return newButterfly; +} + +WriteBarrier<Unknown>* JSObject::createInitialInt32(JSGlobalData& globalData, unsigned length) +{ + Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue)); + Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateInt32); + setButterfly(globalData, newButterfly, newStructure); + return newButterfly->contiguousInt32(); +} + +double* JSObject::createInitialDouble(JSGlobalData& globalData, unsigned length) +{ + Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(double)); + for (unsigned i = newButterfly->vectorLength(); i--;) + newButterfly->contiguousDouble()[i] = QNaN; + Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateDouble); + setButterfly(globalData, newButterfly, newStructure); + return newButterfly->contiguousDouble(); +} + +WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length) +{ + Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue)); Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous); setButterfly(globalData, newButterfly, newStructure); return newButterfly->contiguous(); @@ -577,10 +675,33 @@ ArrayStorage* JSObject::createInitialArrayStorage(JSGlobalData& globalData) return createArrayStorage(globalData, 0, BASE_VECTOR_LEN); } -ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) +WriteBarrier<Unknown>* JSObject::convertUndecidedToInt32(JSGlobalData& globalData) { - ASSERT(hasContiguous(structure()->indexingType())); + ASSERT(hasUndecided(structure()->indexingType())); + setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateInt32)); + return m_butterfly->contiguousInt32(); +} + +double* JSObject::convertUndecidedToDouble(JSGlobalData& globalData) +{ + ASSERT(hasUndecided(structure()->indexingType())); + + for (unsigned i = m_butterfly->vectorLength(); i--;) + m_butterfly->contiguousDouble()[i] = QNaN; + setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateDouble)); + return m_butterfly->contiguousDouble(); +} + +WriteBarrier<Unknown>* JSObject::convertUndecidedToContiguous(JSGlobalData& globalData) +{ + ASSERT(hasUndecided(structure()->indexingType())); + setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous)); + return m_butterfly->contiguous(); +} + +ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(JSGlobalData& globalData, unsigned neededLength) +{ unsigned publicLength = m_butterfly->publicLength(); unsigned propertyCapacity = structure()->outOfLineCapacity(); unsigned propertySize = structure()->outOfLineSize(); @@ -599,7 +720,66 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData newStorage->m_sparseMap.clear(); newStorage->m_indexBias = 0; newStorage->m_numValuesInVector = 0; - for (unsigned i = publicLength; i--;) { + + return newStorage; +} + +ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) +{ + ASSERT(hasUndecided(structure()->indexingType())); + + ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); + // No need to copy elements. + + Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); + setButterfly(globalData, storage->butterfly(), newStructure); + return storage; +} + +ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition) +{ + return convertUndecidedToArrayStorage(globalData, transition, m_butterfly->vectorLength()); +} + +ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData) +{ + return convertUndecidedToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); +} + +double* JSObject::convertInt32ToDouble(JSGlobalData& globalData) +{ + ASSERT(hasInt32(structure()->indexingType())); + + for (unsigned i = m_butterfly->vectorLength(); i--;) { + WriteBarrier<Unknown>* current = &m_butterfly->contiguousInt32()[i]; + double* currentAsDouble = bitwise_cast<double*>(current); + JSValue v = current->get(); + if (!v) { + *currentAsDouble = QNaN; + continue; + } + ASSERT(v.isInt32()); + *currentAsDouble = v.asInt32(); + } + + setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateDouble)); + return m_butterfly->contiguousDouble(); +} + +WriteBarrier<Unknown>* JSObject::convertInt32ToContiguous(JSGlobalData& globalData) +{ + ASSERT(hasInt32(structure()->indexingType())); + + setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous)); + return m_butterfly->contiguous(); +} + +ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) +{ + ASSERT(hasInt32(structure()->indexingType())); + + ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); + for (unsigned i = m_butterfly->publicLength(); i--;) { JSValue v = m_butterfly->contiguous()[i].get(); if (!v) continue; @@ -608,7 +788,82 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData } Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); - setButterfly(globalData, newButterfly, newStructure); + setButterfly(globalData, newStorage->butterfly(), newStructure); + return newStorage; +} + +ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition) +{ + return convertInt32ToArrayStorage(globalData, transition, m_butterfly->vectorLength()); +} + +ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData) +{ + return convertInt32ToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); +} + +WriteBarrier<Unknown>* JSObject::convertDoubleToContiguous(JSGlobalData& globalData) +{ + ASSERT(hasDouble(structure()->indexingType())); + + for (unsigned i = m_butterfly->vectorLength(); i--;) { + double* current = &m_butterfly->contiguousDouble()[i]; + WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current); + double value = *current; + if (value != value) { + currentAsValue->clear(); + continue; + } + currentAsValue->setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value)); + } + + setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous)); + return m_butterfly->contiguous(); +} + +ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) +{ + ASSERT(hasDouble(structure()->indexingType())); + + ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); + for (unsigned i = m_butterfly->publicLength(); i--;) { + double value = m_butterfly->contiguousDouble()[i]; + if (value != value) + continue; + newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value)); + newStorage->m_numValuesInVector++; + } + + Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); + setButterfly(globalData, newStorage->butterfly(), newStructure); + return newStorage; +} + +ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition) +{ + return convertDoubleToArrayStorage(globalData, transition, m_butterfly->vectorLength()); +} + +ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData) +{ + return convertDoubleToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); +} + +ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) +{ + ASSERT(hasContiguous(structure()->indexingType())); + + ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); + for (unsigned i = m_butterfly->publicLength(); i--;) { + JSValue v = m_butterfly->contiguous()[i].get(); + if (!v) + continue; + newStorage->m_vector[i].setWithoutWriteBarrier(v); + newStorage->m_numValuesInVector++; + } + + Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); + setButterfly(globalData, newStorage->butterfly(), newStructure); return newStorage; } @@ -622,48 +877,154 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData return convertContiguousToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); } -WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData) +void JSObject::convertUndecidedForValue(JSGlobalData& globalData, JSValue value) +{ + if (value.isInt32()) { + convertUndecidedToInt32(globalData); + return; + } + + if (value.isDouble()) { + convertUndecidedToDouble(globalData); + return; + } + + convertUndecidedToContiguous(globalData); +} + +void JSObject::convertInt32ForValue(JSGlobalData& globalData, JSValue value) +{ + ASSERT(!value.isInt32()); + + if (value.isDouble()) { + convertInt32ToDouble(globalData); + return; + } + + convertInt32ToContiguous(globalData); +} + +void JSObject::setIndexQuicklyToUndecided(JSGlobalData& globalData, unsigned index, JSValue value) +{ + ASSERT(index < m_butterfly->publicLength()); + ASSERT(index < m_butterfly->vectorLength()); + convertUndecidedForValue(globalData, value); + setIndexQuickly(globalData, index, value); +} + +void JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(JSGlobalData& globalData, unsigned index, JSValue value) +{ + ASSERT(!value.isInt32()); + convertInt32ForValue(globalData, value); + setIndexQuickly(globalData, index, value); +} + +void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(JSGlobalData& globalData, unsigned index, JSValue value) +{ + ASSERT(!value.isNumber() || value.asNumber() != value.asNumber()); + convertDoubleToContiguous(globalData); + setIndexQuickly(globalData, index, value); +} + +WriteBarrier<Unknown>* JSObject::ensureInt32Slow(JSGlobalData& globalData) { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) return 0; - return createInitialContiguous(globalData, 0); + return createInitialInt32(globalData, 0); + + case ALL_UNDECIDED_INDEXING_TYPES: + return convertUndecidedToInt32(globalData); + + case ALL_DOUBLE_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return 0; default: - ASSERT_NOT_REACHED(); + CRASH(); return 0; } } -ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData) +double* JSObject::ensureDoubleSlow(JSGlobalData& globalData) { switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) + return 0; + return createInitialDouble(globalData, 0); + + case ALL_UNDECIDED_INDEXING_TYPES: + return convertUndecidedToDouble(globalData); + + case ALL_INT32_INDEXING_TYPES: + return convertInt32ToDouble(globalData); + case ALL_CONTIGUOUS_INDEXING_TYPES: - ASSERT(!indexingShouldBeSparse()); - ASSERT(!structure()->needsSlowPutIndexing()); - return convertContiguousToArrayStorage(globalData); + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return 0; + default: + CRASH(); + return 0; + } +} + +WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData) +{ + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: - if (UNLIKELY(indexingShouldBeSparse())) - return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData); - return createInitialArrayStorage(globalData); + if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) + return 0; + return createInitialContiguous(globalData, 0); + + case ALL_UNDECIDED_INDEXING_TYPES: + return convertUndecidedToContiguous(globalData); + + case ALL_INT32_INDEXING_TYPES: + return convertInt32ToContiguous(globalData); + + case ALL_DOUBLE_INDEXING_TYPES: + return convertDoubleToContiguous(globalData); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return 0; default: - ASSERT_NOT_REACHED(); + CRASH(); return 0; } } -Butterfly* JSObject::ensureIndexedStorageSlow(JSGlobalData& globalData) +ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData) { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: - if (UNLIKELY(structure()->needsSlowPutIndexing())) - return createInitialArrayStorage(globalData)->butterfly(); if (UNLIKELY(indexingShouldBeSparse())) - return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)->butterfly(); - return Butterfly::fromContiguous(createInitialContiguous(globalData, 0)); + return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData); + return createInitialArrayStorage(globalData); + + case ALL_UNDECIDED_INDEXING_TYPES: + ASSERT(!indexingShouldBeSparse()); + ASSERT(!structure()->needsSlowPutIndexing()); + return convertUndecidedToArrayStorage(globalData); + + case ALL_INT32_INDEXING_TYPES: + ASSERT(!indexingShouldBeSparse()); + ASSERT(!structure()->needsSlowPutIndexing()); + return convertInt32ToArrayStorage(globalData); + + case ALL_DOUBLE_INDEXING_TYPES: + ASSERT(!indexingShouldBeSparse()); + ASSERT(!structure()->needsSlowPutIndexing()); + return convertDoubleToArrayStorage(globalData); + + case ALL_CONTIGUOUS_INDEXING_TYPES: + ASSERT(!indexingShouldBeSparse()); + ASSERT(!structure()->needsSlowPutIndexing()); + return convertContiguousToArrayStorage(globalData); default: ASSERT_NOT_REACHED(); @@ -674,13 +1035,6 @@ Butterfly* JSObject::ensureIndexedStorageSlow(JSGlobalData& globalData) ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData& globalData) { switch (structure()->indexingType()) { - case ALL_CONTIGUOUS_INDEXING_TYPES: - // FIXME: This could be made way more efficient, if we cared. - return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData)); - - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage()); - case ALL_BLANK_INDEXING_TYPES: { createArrayStorage(globalData, 0, 0); SparseArrayValueMap* map = allocateSparseIndexMap(globalData); @@ -688,8 +1042,23 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J return arrayStorage(); } + case ALL_UNDECIDED_INDEXING_TYPES: + return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertUndecidedToArrayStorage(globalData)); + + case ALL_INT32_INDEXING_TYPES: + return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertInt32ToArrayStorage(globalData)); + + case ALL_DOUBLE_INDEXING_TYPES: + return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertDoubleToArrayStorage(globalData)); + + case ALL_CONTIGUOUS_INDEXING_TYPES: + return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData)); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage()); + default: - ASSERT_NOT_REACHED(); + CRASH(); return 0; } } @@ -697,10 +1066,21 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData) { switch (structure()->indexingType()) { - case ALL_CONTIGUOUS_INDEXING_TYPES: { + case ALL_UNDECIDED_INDEXING_TYPES: + convertUndecidedToArrayStorage(globalData, AllocateSlowPutArrayStorage); + break; + + case ALL_INT32_INDEXING_TYPES: + convertInt32ToArrayStorage(globalData, AllocateSlowPutArrayStorage); + break; + + case ALL_DOUBLE_INDEXING_TYPES: + convertDoubleToArrayStorage(globalData, AllocateSlowPutArrayStorage); + break; + + case ALL_CONTIGUOUS_INDEXING_TYPES: convertContiguousToArrayStorage(globalData, AllocateSlowPutArrayStorage); break; - } case NonArrayWithArrayStorage: case ArrayWithArrayStorage: { @@ -710,7 +1090,7 @@ void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData) } default: - ASSERT_NOT_REACHED(); + CRASH(); break; } } @@ -877,8 +1257,10 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) switch (thisObject->structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: return true; + case ALL_INT32_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: { Butterfly* butterfly = thisObject->m_butterfly; if (i >= butterfly->vectorLength()) @@ -887,6 +1269,14 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) return true; } + case ALL_DOUBLE_INDEXING_TYPES: { + Butterfly* butterfly = thisObject->m_butterfly; + if (i >= butterfly->vectorLength()) + return true; + butterfly->contiguousDouble()[i] = QNaN; + return true; + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = thisObject->m_butterfly->arrayStorage(); @@ -1058,8 +1448,10 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa // which almost certainly means a different structure for PropertyNameArray. switch (object->structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: break; + case ALL_INT32_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: { Butterfly* butterfly = object->m_butterfly; unsigned usedLength = butterfly->publicLength(); @@ -1071,6 +1463,18 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa break; } + case ALL_DOUBLE_INDEXING_TYPES: { + Butterfly* butterfly = object->m_butterfly; + unsigned usedLength = butterfly->publicLength(); + for (unsigned i = 0; i < usedLength; ++i) { + double value = butterfly->contiguousDouble()[i]; + if (value != value) + continue; + propertyNames.add(Identifier::from(exec, i)); + } + break; + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = object->m_butterfly->arrayStorage(); @@ -1460,9 +1864,10 @@ bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, J return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow); } -void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState* exec, unsigned i, JSValue value) +template<IndexingType indexingShape> +void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, unsigned i, JSValue value) { - ASSERT(hasContiguous(structure()->indexingType())); + ASSERT((structure()->indexingType() & IndexingShapeMask) == indexingShape); ASSERT(!indexingShouldBeSparse()); // For us to get here, the index is either greater than the public length, or greater than @@ -1473,9 +1878,9 @@ void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState if (i >= MAX_ARRAY_INDEX - 1 || (i >= MIN_SPARSE_ARRAY_INDEX - && !isDenseEnoughForVector(i, countElementsInContiguous(m_butterfly)))) { + && !isDenseEnoughForVector(i, countElements<indexingShape>(m_butterfly)))) { ASSERT(i <= MAX_ARRAY_INDEX); - convertContiguousToArrayStorage(globalData, AllocateArrayStorage); + ensureArrayStorageSlow(globalData); SparseArrayValueMap* map = allocateSparseIndexMap(globalData); map->putEntry(exec, this, i, value, false); ASSERT(i >= arrayStorage()->length()); @@ -1483,10 +1888,30 @@ void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState return; } - ensureContiguousLength(globalData, i + 1); + ensureLength(globalData, i + 1); ASSERT(i < m_butterfly->vectorLength()); - m_butterfly->contiguous()[i].set(globalData, this, value); + switch (indexingShape) { + case Int32Shape: + ASSERT(value.isInt32()); + m_butterfly->contiguousInt32()[i].setWithoutWriteBarrier(value); + break; + + case DoubleShape: { + ASSERT(value.isNumber()); + double valueAsDouble = value.asNumber(); + ASSERT(valueAsDouble == valueAsDouble); + m_butterfly->contiguousDouble()[i] = valueAsDouble; + break; + } + + case ContiguousShape: + m_butterfly->contiguous()[i].set(globalData, this, value); + break; + + default: + CRASH(); + } } void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage) @@ -1592,8 +2017,23 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue break; } + case ALL_UNDECIDED_INDEXING_TYPES: { + CRASH(); + break; + } + + case ALL_INT32_INDEXING_TYPES: { + putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value); + break; + } + + case ALL_DOUBLE_INDEXING_TYPES: { + putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value); + break; + } + case ALL_CONTIGUOUS_INDEXING_TYPES: { - putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value); + putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value); break; } @@ -1724,12 +2164,49 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV return true; } + case ALL_UNDECIDED_INDEXING_TYPES: { + convertUndecidedForValue(exec->globalData(), value); + // Reloop. + return putDirectIndex(exec, i, value, attributes, mode); + } + + case ALL_INT32_INDEXING_TYPES: { + if (attributes & (ReadOnly | Accessor)) { + return putDirectIndexBeyondVectorLengthWithArrayStorage( + exec, i, value, attributes, mode, convertInt32ToArrayStorage(globalData)); + } + if (!value.isInt32()) { + convertInt32ForValue(globalData, value); + return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode); + } + putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value); + return true; + } + + case ALL_DOUBLE_INDEXING_TYPES: { + if (attributes & (ReadOnly | Accessor)) { + return putDirectIndexBeyondVectorLengthWithArrayStorage( + exec, i, value, attributes, mode, convertDoubleToArrayStorage(globalData)); + } + if (!value.isNumber()) { + convertDoubleToContiguous(globalData); + return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode); + } + double valueAsDouble = value.asNumber(); + if (valueAsDouble != valueAsDouble) { + convertDoubleToContiguous(globalData); + return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode); + } + putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value); + return true; + } + case ALL_CONTIGUOUS_INDEXING_TYPES: { if (attributes & (ReadOnly | Accessor)) { return putDirectIndexBeyondVectorLengthWithArrayStorage( exec, i, value, attributes, mode, convertContiguousToArrayStorage(globalData)); } - putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value); + putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value); return true; } @@ -1769,33 +2246,65 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength) unsigned vectorLength; unsigned length; - switch (structure()->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - vectorLength = 0; - length = 0; - break; - case ALL_CONTIGUOUS_INDEXING_TYPES: - case ALL_ARRAY_STORAGE_INDEXING_TYPES: + if (hasIndexedProperties(structure()->indexingType())) { vectorLength = m_butterfly->vectorLength(); length = m_butterfly->publicLength(); - break; - default: - CRASH(); - return 0; + } else { + vectorLength = 0; + length = 0; } + return getNewVectorLength(vectorLength, length, desiredLength); } -unsigned JSObject::countElementsInContiguous(Butterfly* butterfly) +template<IndexingType indexingShape> +unsigned JSObject::countElements(Butterfly* butterfly) { unsigned numValues = 0; for (unsigned i = butterfly->publicLength(); i--;) { - if (butterfly->contiguous()[i]) - numValues++; + switch (indexingShape) { + case Int32Shape: + case ContiguousShape: + if (butterfly->contiguous()[i]) + numValues++; + break; + + case DoubleShape: { + double value = butterfly->contiguousDouble()[i]; + if (value == value) + numValues++; + break; + } + + default: + CRASH(); + } } return numValues; } +unsigned JSObject::countElements() +{ + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: + return 0; + + case ALL_INT32_INDEXING_TYPES: + return countElements<Int32Shape>(m_butterfly); + + case ALL_DOUBLE_INDEXING_TYPES: + return countElements<DoubleShape>(m_butterfly); + + case ALL_CONTIGUOUS_INDEXING_TYPES: + return countElements<ContiguousShape>(m_butterfly); + + default: + CRASH(); + return 0; + } +} + bool JSObject::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 @@ -1839,19 +2348,24 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength return true; } -void JSObject::ensureContiguousLengthSlow(JSGlobalData& globalData, unsigned length) +void JSObject::ensureLengthSlow(JSGlobalData& globalData, unsigned length) { ASSERT(length < MAX_ARRAY_INDEX); - ASSERT(hasContiguous(structure()->indexingType())); + ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType())); ASSERT(length > m_butterfly->vectorLength()); unsigned newVectorLength = std::min( length << 1, MAX_STORAGE_VECTOR_LENGTH); + unsigned oldVectorLength = m_butterfly->vectorLength(); m_butterfly = m_butterfly->growArrayRight( globalData, structure(), structure()->outOfLineCapacity(), true, - m_butterfly->vectorLength() * sizeof(EncodedJSValue), + oldVectorLength * sizeof(EncodedJSValue), newVectorLength * sizeof(EncodedJSValue)); + if (hasDouble(structure()->indexingType())) { + for (unsigned i = oldVectorLength; i < newVectorLength; ++i) + m_butterfly->contiguousDouble()[i] = QNaN; + } m_butterfly->setVectorLength(newVectorLength); } @@ -1881,8 +2395,10 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope switch (object->structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: return false; + case ALL_INT32_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: { Butterfly* butterfly = object->m_butterfly; if (i >= butterfly->vectorLength()) @@ -1894,6 +2410,17 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope return true; } + case ALL_DOUBLE_INDEXING_TYPES: { + Butterfly* butterfly = object->m_butterfly; + if (i >= butterfly->vectorLength()) + return false; + double value = butterfly->contiguousDouble()[i]; + if (value != value) + return false; + descriptor.setDescriptor(JSValue(JSValue::EncodeAsDouble, value), 0); + return true; + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = object->m_butterfly->arrayStorage(); if (i >= storage->length()) diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index 82455390f..f9ae73ed4 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -151,30 +151,16 @@ public: unsigned getArrayLength() const { - switch (structure()->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: + if (!hasIndexedProperties(structure()->indexingType())) return 0; - case ALL_CONTIGUOUS_INDEXING_TYPES: - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->publicLength(); - default: - ASSERT_NOT_REACHED(); - return 0; - } + return m_butterfly->publicLength(); } unsigned getVectorLength() { - switch (structure()->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: + if (!hasIndexedProperties(structure()->indexingType())) return 0; - case ALL_CONTIGUOUS_INDEXING_TYPES: - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->vectorLength(); - default: - ASSERT_NOT_REACHED(); - return 0; - } + return m_butterfly->vectorLength(); } JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); @@ -214,9 +200,19 @@ public: { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: return false; + case ALL_INT32_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return i < m_butterfly->vectorLength() && m_butterfly->contiguous()[i]; + case ALL_DOUBLE_INDEXING_TYPES: { + if (i >= m_butterfly->vectorLength()) + return false; + double value = m_butterfly->contiguousDouble()[i]; + if (value != value) + return false; + return true; + } case ALL_ARRAY_STORAGE_INDEXING_TYPES: return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i]; default: @@ -228,8 +224,11 @@ public: JSValue getIndexQuickly(unsigned i) { switch (structure()->indexingType()) { + case ALL_INT32_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return m_butterfly->contiguous()[i].get(); + case ALL_DOUBLE_INDEXING_TYPES: + return JSValue(JSValue::EncodeAsDouble, m_butterfly->contiguousDouble()[i]); case ALL_ARRAY_STORAGE_INDEXING_TYPES: return m_butterfly->arrayStorage()->m_vector[i].get(); default: @@ -243,10 +242,19 @@ public: switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: break; + case ALL_INT32_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: if (i < m_butterfly->publicLength()) return m_butterfly->contiguous()[i].get(); break; + case ALL_DOUBLE_INDEXING_TYPES: { + if (i >= m_butterfly->publicLength()) + break; + double result = m_butterfly->contiguousDouble()[i]; + if (result != result) + break; + return JSValue(JSValue::EncodeAsDouble, result); + } case ALL_ARRAY_STORAGE_INDEXING_TYPES: if (i < m_butterfly->arrayStorage()->vectorLength()) return m_butterfly->arrayStorage()->m_vector[i].get(); @@ -279,7 +287,10 @@ public: { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: return false; + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: case NonArrayWithArrayStorage: case ArrayWithArrayStorage: @@ -298,7 +309,10 @@ public: { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: return false; + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_ARRAY_STORAGE_INDEXING_TYPES: return i < m_butterfly->vectorLength(); @@ -311,6 +325,14 @@ public: void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v) { switch (structure()->indexingType()) { + case ALL_INT32_INDEXING_TYPES: { + ASSERT(i < m_butterfly->vectorLength()); + if (!v.isInt32()) { + convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v); + return; + } + // Fall through to contiguous case. + } case ALL_CONTIGUOUS_INDEXING_TYPES: { ASSERT(i < m_butterfly->vectorLength()); m_butterfly->contiguous()[i].set(globalData, this, v); @@ -318,6 +340,22 @@ public: m_butterfly->setPublicLength(i + 1); break; } + case ALL_DOUBLE_INDEXING_TYPES: { + ASSERT(i < m_butterfly->vectorLength()); + if (!v.isNumber()) { + convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); + return; + } + double value = v.asNumber(); + if (value != value) { + convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); + return; + } + m_butterfly->contiguousDouble()[i] = value; + if (i >= m_butterfly->publicLength()) + m_butterfly->setPublicLength(i + 1); + break; + } case ALL_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = m_butterfly->arrayStorage(); WriteBarrier<Unknown>& x = storage->m_vector[i]; @@ -338,12 +376,40 @@ public: void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v) { switch (structure()->indexingType()) { + case ALL_UNDECIDED_INDEXING_TYPES: { + setIndexQuicklyToUndecided(globalData, i, v); + break; + } + case ALL_INT32_INDEXING_TYPES: { + ASSERT(i < m_butterfly->publicLength()); + ASSERT(i < m_butterfly->vectorLength()); + if (!v.isInt32()) { + convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v); + break; + } + // Fall through. + } case ALL_CONTIGUOUS_INDEXING_TYPES: { ASSERT(i < m_butterfly->publicLength()); ASSERT(i < m_butterfly->vectorLength()); m_butterfly->contiguous()[i].set(globalData, this, v); break; } + case ALL_DOUBLE_INDEXING_TYPES: { + ASSERT(i < m_butterfly->publicLength()); + ASSERT(i < m_butterfly->vectorLength()); + if (!v.isNumber()) { + convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); + return; + } + double value = v.asNumber(); + if (value != value) { + convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); + return; + } + m_butterfly->contiguousDouble()[i] = value; + break; + } case ALL_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = m_butterfly->arrayStorage(); ASSERT(i < storage->length()); @@ -360,6 +426,9 @@ public: { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return false; case ALL_ARRAY_STORAGE_INDEXING_TYPES: @@ -374,6 +443,9 @@ public: { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return false; case ALL_ARRAY_STORAGE_INDEXING_TYPES: @@ -571,6 +643,30 @@ public: // foo->attemptToInterceptPutByIndexOnHole(...); bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow); + // Returns 0 if int32 storage cannot be created - either because + // indexing should be sparse, we're having a bad time, or because + // we already have a more general form of storage (double, + // contiguous, array storage). + WriteBarrier<Unknown>* ensureInt32(JSGlobalData& globalData) + { + if (LIKELY(hasInt32(structure()->indexingType()))) + return m_butterfly->contiguousInt32(); + + return ensureInt32Slow(globalData); + } + + // Returns 0 if double storage cannot be created - either because + // indexing should be sparse, we're having a bad time, or because + // we already have a more general form of storage (contiguous, + // or array storage). + double* ensureDouble(JSGlobalData& globalData) + { + if (LIKELY(hasDouble(structure()->indexingType()))) + return m_butterfly->contiguousDouble(); + + return ensureDoubleSlow(globalData); + } + // Returns 0 if contiguous storage cannot be created - either because // indexing should be sparse or because we're having a bad time. WriteBarrier<Unknown>* ensureContiguous(JSGlobalData& globalData) @@ -593,14 +689,6 @@ public: return ensureArrayStorageSlow(globalData); } - Butterfly* ensureIndexedStorage(JSGlobalData& globalData) - { - if (LIKELY(hasIndexedProperties(structure()->indexingType()))) - return m_butterfly; - - return ensureIndexedStorageSlow(globalData); - } - static size_t offsetOfInlineStorage(); static ptrdiff_t butterflyOffset() @@ -661,19 +749,47 @@ protected: return 0; } } - + + Butterfly* createInitialUndecided(JSGlobalData&, unsigned length); + WriteBarrier<Unknown>* createInitialInt32(JSGlobalData&, unsigned length); + double* createInitialDouble(JSGlobalData&, unsigned length); + WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length); + + void convertUndecidedForValue(JSGlobalData&, JSValue); + void convertInt32ForValue(JSGlobalData&, JSValue); + ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength); ArrayStorage* createInitialArrayStorage(JSGlobalData&); - WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length); + + WriteBarrier<Unknown>* convertUndecidedToInt32(JSGlobalData&); + double* convertUndecidedToDouble(JSGlobalData&); + WriteBarrier<Unknown>* convertUndecidedToContiguous(JSGlobalData&); + ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); + ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition); + ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&); + + double* convertInt32ToDouble(JSGlobalData&); + WriteBarrier<Unknown>* convertInt32ToContiguous(JSGlobalData&); + ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); + ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition); + ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&); + + WriteBarrier<Unknown>* convertDoubleToContiguous(JSGlobalData&); + ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); + ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition); + ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&); + ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition); ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&); + ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&); bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException); - void putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState*, unsigned propertyName, JSValue); + template<IndexingType indexingShape> + void putByIndexBeyondVectorLengthWithoutAttributes(ExecState*, unsigned propertyName, JSValue); void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*); bool increaseVectorLength(JSGlobalData&, unsigned newLength); @@ -687,24 +803,33 @@ protected: // Call this if you want setIndexQuickly to succeed and you're sure that // the array is contiguous. - void ensureContiguousLength(JSGlobalData& globalData, unsigned length) + void ensureLength(JSGlobalData& globalData, unsigned length) { ASSERT(length < MAX_ARRAY_INDEX); - ASSERT(hasContiguous(structure()->indexingType())); + ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType())); if (m_butterfly->vectorLength() < length) - ensureContiguousLengthSlow(globalData, length); + ensureLengthSlow(globalData, length); if (m_butterfly->publicLength() < length) m_butterfly->setPublicLength(length); } - unsigned countElementsInContiguous(Butterfly*); + template<IndexingType indexingShape> + unsigned countElements(Butterfly*); + // This is relevant to undecided, int32, double, and contiguous. + unsigned countElements(); + + // This strange method returns a pointer to the start of the indexed data + // as if it contained JSValues. But it won't always contain JSValues. + // Make sure you cast this to the appropriate type before using. template<IndexingType indexingType> WriteBarrier<Unknown>* indexingData() { switch (indexingType) { + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return m_butterfly->contiguous(); @@ -720,6 +845,7 @@ protected: WriteBarrier<Unknown>* currentIndexingData() { switch (structure()->indexingType()) { + case ALL_INT32_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return m_butterfly->contiguous(); @@ -732,10 +858,32 @@ protected: } } + JSValue getHolyIndexQuickly(unsigned i) + { + switch (structure()->indexingType()) { + case ALL_INT32_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->contiguous()[i].get(); + case ALL_DOUBLE_INDEXING_TYPES: { + double value = m_butterfly->contiguousDouble()[i]; + if (value == value) + return JSValue(JSValue::EncodeAsDouble, value); + return JSValue(); + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage()->m_vector[i].get(); + default: + CRASH(); + return JSValue(); + } + } + template<IndexingType indexingType> unsigned relevantLength() { switch (indexingType) { + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return m_butterfly->publicLength(); @@ -753,6 +901,8 @@ protected: unsigned currentRelevantLength() { switch (structure()->indexingType()) { + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return m_butterfly->publicLength(); @@ -778,6 +928,8 @@ private: void isObject(); void isString(); + Butterfly* createInitialIndexedStorage(JSGlobalData&, unsigned length, size_t elementSize); + ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*); template<PutMode> @@ -800,11 +952,18 @@ private: JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&); - void ensureContiguousLengthSlow(JSGlobalData&, unsigned length); + ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(JSGlobalData&, unsigned neededLength); + + JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(JSGlobalData&, unsigned index, JSValue); + JS_EXPORT_PRIVATE void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue); + JS_EXPORT_PRIVATE void convertDoubleToContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue); + + void ensureLengthSlow(JSGlobalData&, unsigned length); + WriteBarrier<Unknown>* ensureInt32Slow(JSGlobalData&); + double* ensureDoubleSlow(JSGlobalData&); WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&); ArrayStorage* ensureArrayStorageSlow(JSGlobalData&); - Butterfly* ensureIndexedStorageSlow(JSGlobalData&); protected: Butterfly* m_butterfly; diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp index e7f8cad17..8f245f98d 100644 --- a/Source/JavaScriptCore/runtime/JSValue.cpp +++ b/Source/JavaScriptCore/runtime/JSValue.cpp @@ -215,8 +215,8 @@ char* JSValue::description() const #endif } else if (isCell()) { snprintf( - description, size, "Cell: %p (%p: %s, %s)", - asCell(), asCell()->structure(), asCell()->structure()->classInfo()->className, + description, size, "Cell: %p -> %p (%p: %s, %s)", + asCell(), isObject() ? asObject(*this)->butterfly() : 0, asCell()->structure(), asCell()->structure()->classInfo()->className, indexingTypeToString(asCell()->structure()->indexingTypeIncludingHistory())); } else if (isTrue()) snprintf(description, size, "True"); diff --git a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h b/Source/JavaScriptCore/runtime/JSValueInlines.h index 224982e9e..c5a42f67f 100644 --- a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h +++ b/Source/JavaScriptCore/runtime/JSValueInlines.h @@ -23,8 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSValueInlineMethods_h -#define JSValueInlineMethods_h +#ifndef JSValueInlines_h +#define JSValueInlines_h #include "JSValue.h" @@ -493,4 +493,5 @@ namespace JSC { } // namespace JSC -#endif // JSValueInlineMethods_h +#endif // JSValueInlines_h + diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp index cd854417b..bf27327bf 100644 --- a/Source/JavaScriptCore/runtime/LiteralParser.cpp +++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp @@ -27,8 +27,8 @@ #include "config.h" #include "LiteralParser.h" -#include "ButterflyInlineMethods.h" -#include "CopiedSpaceInlineMethods.h" +#include "ButterflyInlines.h" +#include "CopiedSpaceInlines.h" #include "JSArray.h" #include "JSString.h" #include "Lexer.h" @@ -548,7 +548,7 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState) switch(state) { startParseArray: case StartParseArray: { - JSArray* array = constructEmptyArray(m_exec); + JSArray* array = constructEmptyArray(m_exec, 0); objectStack.append(array); // fallthrough } diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp index 7df047d28..7e74a914b 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -21,8 +21,8 @@ #include "config.h" #include "ObjectConstructor.h" -#include "ButterflyInlineMethods.h" -#include "CopiedSpaceInlineMethods.h" +#include "ButterflyInlines.h" +#include "CopiedSpaceInlines.h" #include "Error.h" #include "ExceptionHelpers.h" #include "JSFunction.h" @@ -182,7 +182,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exe return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested property names of a value that is not an object."))); PropertyNameArray properties(exec); asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, IncludeDontEnumProperties); - JSArray* names = constructEmptyArray(exec); + JSArray* names = constructEmptyArray(exec, 0); size_t numProperties = properties.size(); for (size_t i = 0; i < numProperties; i++) names->push(exec, jsOwnedString(exec, properties[i].string())); @@ -196,7 +196,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec) return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested keys of a value that is not an object."))); PropertyNameArray properties(exec); asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, ExcludeDontEnumProperties); - JSArray* keys = constructEmptyArray(exec); + JSArray* keys = constructEmptyArray(exec, 0); size_t numProperties = properties.size(); for (size_t i = 0; i < numProperties; i++) keys->push(exec, jsOwnedString(exec, properties[i].string())); diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h index 01df7e98c..ed14e895f 100644 --- a/Source/JavaScriptCore/runtime/Operations.h +++ b/Source/JavaScriptCore/runtime/Operations.h @@ -26,7 +26,7 @@ #include "Interpreter.h" #include "JSProxy.h" #include "JSString.h" -#include "JSValueInlineMethods.h" +#include "JSValueInlines.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp index ce9c2d2db..19f3b81ad 100644 --- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp +++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "RegExpMatchesArray.h" -#include "ButterflyInlineMethods.h" +#include "ButterflyInlines.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp index 35de40912..00dd1ed74 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.cpp +++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp @@ -21,8 +21,8 @@ #include "config.h" #include "RegExpObject.h" -#include "ButterflyInlineMethods.h" -#include "CopiedSpaceInlineMethods.h" +#include "ButterflyInlines.h" +#include "CopiedSpaceInlines.h" #include "Error.h" #include "ExceptionHelpers.h" #include "JSArray.h" diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp index 5aafe8bb3..93009d806 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -22,9 +22,9 @@ #include "config.h" #include "StringPrototype.h" -#include "ButterflyInlineMethods.h" +#include "ButterflyInlines.h" #include "CachedCall.h" -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "Error.h" #include "Executable.h" #include "JSGlobalObjectFunctions.h" @@ -870,7 +870,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) return JSValue::encode(jsNull()); } - return JSValue::encode(constructArray(exec, list)); + return JSValue::encode(constructArray(exec, static_cast<ArrayAllocationProfile*>(0), list)); } EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) @@ -973,7 +973,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* 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. - JSArray* result = constructEmptyArray(exec); + JSArray* result = constructEmptyArray(exec, 0); // 4. Let lengthA be 0. unsigned resultLength = 0; @@ -1388,7 +1388,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); - return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", a0.toString(exec)->value(exec), "\">", s, "</font>")); + String color = a0.toWTFString(exec); + color.replaceWithLiteral('"', """); + + return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", color, "\">", s, "</font>")); } EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec) @@ -1433,7 +1436,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec) return JSValue::encode(jsNontrivialString(exec, impl)); } - return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", a0.toString(exec)->value(exec), "\">", s, "</font>")); + String fontSize = a0.toWTFString(exec); + fontSize.replaceWithLiteral('"', """); + + return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", fontSize, "\">", s, "</font>")); } EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec) @@ -1443,7 +1449,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); - return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", a0.toString(exec)->value(exec), "\">", s, "</a>")); + String anchor = a0.toWTFString(exec); + anchor.replaceWithLiteral('"', """); + + return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", anchor, "\">", s, "</a>")); } EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec) @@ -1453,7 +1462,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); - String linkText = a0.toString(exec)->value(exec); + String linkText = a0.toWTFString(exec); + linkText.replaceWithLiteral('"', """); unsigned linkTextSize = linkText.length(); unsigned stringSize = s.length(); diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index e733c7e23..e930c022a 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -543,12 +543,13 @@ Structure* Structure::nonPropertyTransition(JSGlobalData& globalData, Structure* unsigned attributes = toAttributes(transitionKind); IndexingType indexingType = newIndexingType(structure->indexingTypeIncludingHistory(), transitionKind); - JSGlobalObject* globalObject = structure->globalObject(); - if (structure == globalObject->arrayStructure()) { - Structure* transition = globalObject->arrayStructureWithArrayStorage(); - if (transition->indexingTypeIncludingHistory() == indexingType) { - structure->notifyTransitionFromThisStructure(); - return transition; + if (JSGlobalObject* globalObject = structure->m_globalObject.get()) { + if (globalObject->isOriginalArrayStructure(structure)) { + Structure* result = globalObject->originalArrayStructureForIndexingType(indexingType); + if (result->indexingTypeIncludingHistory() == indexingType) { + structure->notifyTransitionFromThisStructure(); + return result; + } } } diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h index 3ab7b2014..5291ed540 100644 --- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h @@ -43,6 +43,9 @@ static const unsigned FirstInternalAttribute = 1 << 6; // Use for transitions th // Support for attributes used to indicate transitions not related to properties. // If any of these are used, the string portion of the key should be 0. enum NonPropertyTransition { + AllocateUndecided, + AllocateInt32, + AllocateDouble, AllocateContiguous, AllocateArrayStorage, AllocateSlowPutArrayStorage, @@ -58,14 +61,23 @@ inline unsigned toAttributes(NonPropertyTransition transition) inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition transition) { switch (transition) { - case AllocateContiguous: + case AllocateUndecided: ASSERT(!hasIndexedProperties(oldType)); - return oldType | ContiguousShape; + return oldType | UndecidedShape; + case AllocateInt32: + ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType)); + return (oldType & ~IndexingShapeMask) | Int32Shape; + case AllocateDouble: + ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType)); + return (oldType & ~IndexingShapeMask) | DoubleShape; + case AllocateContiguous: + ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType)); + return (oldType & ~IndexingShapeMask) | ContiguousShape; case AllocateArrayStorage: - ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType)); + ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType)); return (oldType & ~IndexingShapeMask) | ArrayStorageShape; case AllocateSlowPutArrayStorage: - ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType)); + ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType) || hasContiguous(oldType)); return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; case SwitchToSlowPutArrayStorage: ASSERT(hasFastArrayStorage(oldType)); |