From de4f791e30be4e4239b381c11745ffa4d87ddb8b Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 9 Nov 2012 12:15:52 +0100 Subject: Imported WebKit commit e2c32e2f53e02d388e70b9db88b91d8d9d28fc84 (http://svn.webkit.org/repository/webkit/trunk@133952) Revert back to an older snapshot that should build on ARM --- Source/JavaScriptCore/API/JSObjectRef.cpp | 8 +- Source/JavaScriptCore/CMakeLists.txt | 1 - Source/JavaScriptCore/ChangeLog | 656 ------------- Source/JavaScriptCore/DerivedSources.pri | 2 +- Source/JavaScriptCore/GNUmakefile.list.am | 18 +- Source/JavaScriptCore/JavaScriptCore.pro | 4 +- .../JavaScriptCore/JavaScriptCore.def | 6 +- .../JavaScriptCore/JavaScriptCore.vcproj | 22 +- .../JavaScriptCore.xcodeproj/project.pbxproj | 76 +- Source/JavaScriptCore/Target.pri | 1 - .../assembler/AbstractMacroAssembler.h | 7 - .../assembler/MacroAssemblerX86Common.h | 4 - Source/JavaScriptCore/assembler/X86Assembler.h | 9 - .../bytecode/ArrayAllocationProfile.cpp | 40 - .../bytecode/ArrayAllocationProfile.h | 80 -- Source/JavaScriptCore/bytecode/ArrayProfile.cpp | 7 - Source/JavaScriptCore/bytecode/ArrayProfile.h | 48 +- Source/JavaScriptCore/bytecode/ByValInfo.h | 8 - Source/JavaScriptCore/bytecode/CodeBlock.cpp | 55 +- Source/JavaScriptCore/bytecode/CodeBlock.h | 12 - Source/JavaScriptCore/bytecode/DFGExitProfile.h | 2 - Source/JavaScriptCore/bytecode/Instruction.h | 5 +- Source/JavaScriptCore/bytecode/Opcode.h | 6 +- Source/JavaScriptCore/bytecode/SpeculatedType.h | 26 - .../JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp | 19 +- Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h | 11 +- .../bytecompiler/BytecodeGenerator.cpp | 13 - .../bytecompiler/BytecodeGenerator.h | 1 - Source/JavaScriptCore/debugger/Debugger.cpp | 2 +- Source/JavaScriptCore/dfg/DFGAbstractState.cpp | 136 +-- Source/JavaScriptCore/dfg/DFGAbstractState.h | 43 +- Source/JavaScriptCore/dfg/DFGArrayMode.cpp | 241 ++--- Source/JavaScriptCore/dfg/DFGArrayMode.h | 29 +- Source/JavaScriptCore/dfg/DFGBasicBlock.h | 3 - Source/JavaScriptCore/dfg/DFGBranchDirection.h | 88 -- Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | 39 +- Source/JavaScriptCore/dfg/DFGCCallHelpers.h | 78 -- .../dfg/DFGCFGSimplificationPhase.cpp | 6 +- .../dfg/DFGCallArrayAllocatorSlowPathGenerator.h | 4 +- Source/JavaScriptCore/dfg/DFGFixupPhase.cpp | 64 +- Source/JavaScriptCore/dfg/DFGGraph.cpp | 5 - Source/JavaScriptCore/dfg/DFGGraph.h | 12 +- Source/JavaScriptCore/dfg/DFGNode.h | 67 -- Source/JavaScriptCore/dfg/DFGOperations.cpp | 69 +- Source/JavaScriptCore/dfg/DFGOperations.h | 8 +- .../dfg/DFGPredictionPropagationPhase.cpp | 75 +- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp | 162 +--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h | 46 - .../JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp | 511 ++-------- Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp | 348 +------ Source/JavaScriptCore/heap/ConservativeRoots.cpp | 4 +- Source/JavaScriptCore/heap/CopiedBlock.h | 2 +- Source/JavaScriptCore/heap/CopiedSpace.cpp | 2 +- .../JavaScriptCore/heap/CopiedSpaceInlineMethods.h | 185 ++++ Source/JavaScriptCore/heap/CopiedSpaceInlines.h | 186 ---- Source/JavaScriptCore/heap/CopyVisitor.cpp | 2 +- .../JavaScriptCore/heap/CopyVisitorInlineMethods.h | 119 +++ Source/JavaScriptCore/heap/CopyVisitorInlines.h | 120 --- Source/JavaScriptCore/heap/GCThread.cpp | 2 +- Source/JavaScriptCore/heap/GCThreadSharedData.cpp | 4 +- Source/JavaScriptCore/heap/HandleStack.cpp | 2 +- Source/JavaScriptCore/heap/Heap.cpp | 4 +- Source/JavaScriptCore/heap/HeapRootVisitor.h | 2 +- Source/JavaScriptCore/heap/HeapStatistics.cpp | 12 +- Source/JavaScriptCore/heap/HeapStatistics.h | 4 +- Source/JavaScriptCore/heap/MarkStack.cpp | 8 +- .../JavaScriptCore/heap/MarkStackInlineMethods.h | 113 +++ Source/JavaScriptCore/heap/MarkStackInlines.h | 114 --- Source/JavaScriptCore/heap/SlotVisitor.cpp | 2 +- Source/JavaScriptCore/heap/SlotVisitor.h | 2 +- .../JavaScriptCore/heap/SlotVisitorInlineMethods.h | 174 ++++ Source/JavaScriptCore/heap/SlotVisitorInlines.h | 174 ---- Source/JavaScriptCore/jit/HostCallReturnValue.cpp | 2 +- Source/JavaScriptCore/jit/JIT.cpp | 2 +- Source/JavaScriptCore/jit/JIT.h | 19 +- Source/JavaScriptCore/jit/JITArithmetic.cpp | 12 +- Source/JavaScriptCore/jit/JITArithmetic32_64.cpp | 2 +- Source/JavaScriptCore/jit/JITCall.cpp | 2 +- Source/JavaScriptCore/jit/JITCall32_64.cpp | 2 +- Source/JavaScriptCore/jit/JITExceptions.cpp | 2 +- Source/JavaScriptCore/jit/JITInlineMethods.h | 1001 +++++++++++++++++++ Source/JavaScriptCore/jit/JITInlines.h | 1013 -------------------- Source/JavaScriptCore/jit/JITOpcodes.cpp | 7 +- Source/JavaScriptCore/jit/JITOpcodes32_64.cpp | 2 +- Source/JavaScriptCore/jit/JITPropertyAccess.cpp | 91 +- .../JavaScriptCore/jit/JITPropertyAccess32_64.cpp | 74 +- Source/JavaScriptCore/jit/JITStubs.cpp | 13 +- Source/JavaScriptCore/jit/JITStubs.h | 2 - Source/JavaScriptCore/jsc.cpp | 6 +- Source/JavaScriptCore/llint/LLIntSlowPaths.cpp | 8 +- .../JavaScriptCore/llint/LowLevelInterpreter.asm | 17 +- .../llint/LowLevelInterpreter32_64.asm | 83 +- .../JavaScriptCore/llint/LowLevelInterpreter64.asm | 79 +- Source/JavaScriptCore/offlineasm/x86.rb | 34 +- Source/JavaScriptCore/runtime/Arguments.h | 446 ++++----- Source/JavaScriptCore/runtime/ArrayConstructor.cpp | 14 +- Source/JavaScriptCore/runtime/ArrayConstructor.h | 54 +- Source/JavaScriptCore/runtime/ArrayPrototype.cpp | 16 +- Source/JavaScriptCore/runtime/ArrayPrototype.h | 32 +- Source/JavaScriptCore/runtime/Butterfly.h | 6 - .../runtime/ButterflyInlineMethods.h | 179 ++++ Source/JavaScriptCore/runtime/ButterflyInlines.h | 180 ---- Source/JavaScriptCore/runtime/CodeCache.cpp | 37 +- Source/JavaScriptCore/runtime/CodeCache.h | 50 +- Source/JavaScriptCore/runtime/Executable.cpp | 5 +- Source/JavaScriptCore/runtime/Executable.h | 2 +- .../JavaScriptCore/runtime/FunctionPrototype.cpp | 2 +- .../runtime/IndexingHeaderInlineMethods.h | 61 ++ .../JavaScriptCore/runtime/IndexingHeaderInlines.h | 64 -- Source/JavaScriptCore/runtime/IndexingType.cpp | 55 -- Source/JavaScriptCore/runtime/IndexingType.h | 46 +- Source/JavaScriptCore/runtime/JSActivation.h | 2 +- Source/JavaScriptCore/runtime/JSArray.cpp | 454 +-------- Source/JavaScriptCore/runtime/JSArray.h | 36 +- Source/JavaScriptCore/runtime/JSCell.h | 4 +- Source/JavaScriptCore/runtime/JSGlobalObject.cpp | 28 +- Source/JavaScriptCore/runtime/JSGlobalObject.h | 56 +- Source/JavaScriptCore/runtime/JSObject.cpp | 661 ++----------- Source/JavaScriptCore/runtime/JSObject.h | 229 +---- Source/JavaScriptCore/runtime/JSValue.cpp | 4 +- .../JavaScriptCore/runtime/JSValueInlineMethods.h | 496 ++++++++++ Source/JavaScriptCore/runtime/JSValueInlines.h | 497 ---------- Source/JavaScriptCore/runtime/LiteralParser.cpp | 6 +- .../JavaScriptCore/runtime/ObjectConstructor.cpp | 8 +- Source/JavaScriptCore/runtime/Operations.h | 2 +- .../JavaScriptCore/runtime/RegExpMatchesArray.cpp | 2 +- Source/JavaScriptCore/runtime/RegExpObject.cpp | 4 +- Source/JavaScriptCore/runtime/StringPrototype.cpp | 26 +- Source/JavaScriptCore/runtime/Structure.cpp | 13 +- .../runtime/StructureTransitionTable.h | 20 +- 130 files changed, 3468 insertions(+), 7222 deletions(-) delete mode 100644 Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp delete mode 100644 Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h delete mode 100644 Source/JavaScriptCore/dfg/DFGBranchDirection.h create mode 100644 Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h delete mode 100644 Source/JavaScriptCore/heap/CopiedSpaceInlines.h create mode 100644 Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h delete mode 100644 Source/JavaScriptCore/heap/CopyVisitorInlines.h create mode 100644 Source/JavaScriptCore/heap/MarkStackInlineMethods.h delete mode 100644 Source/JavaScriptCore/heap/MarkStackInlines.h create mode 100644 Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h delete mode 100644 Source/JavaScriptCore/heap/SlotVisitorInlines.h create mode 100644 Source/JavaScriptCore/jit/JITInlineMethods.h delete mode 100644 Source/JavaScriptCore/jit/JITInlines.h create mode 100644 Source/JavaScriptCore/runtime/ButterflyInlineMethods.h delete mode 100644 Source/JavaScriptCore/runtime/ButterflyInlines.h create mode 100644 Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h delete mode 100644 Source/JavaScriptCore/runtime/IndexingHeaderInlines.h create mode 100644 Source/JavaScriptCore/runtime/JSValueInlineMethods.h delete mode 100644 Source/JavaScriptCore/runtime/JSValueInlines.h (limited to 'Source/JavaScriptCore') diff --git a/Source/JavaScriptCore/API/JSObjectRef.cpp b/Source/JavaScriptCore/API/JSObjectRef.cpp index c62efc60d..491fa988f 100644 --- a/Source/JavaScriptCore/API/JSObjectRef.cpp +++ b/Source/JavaScriptCore/API/JSObjectRef.cpp @@ -29,9 +29,9 @@ #include "JSObjectRefPrivate.h" #include "APICast.h" -#include "ButterflyInlines.h" +#include "ButterflyInlineMethods.h" #include "CodeBlock.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.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, static_cast(0), argList); + result = constructArray(exec, argList); } else - result = constructEmptyArray(exec, 0); + result = constructEmptyArray(exec); if (exec->hadException()) { if (exception) diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index bfaca5673..393db67c3 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -40,7 +40,6 @@ 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 dbe22d11e..320b1cfbe 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,659 +1,3 @@ -2012-11-09 Csaba Osztrogonác - - [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 - - ArrayPrototype.h should have correct indentation - - Rubber stamped by Sam Weinig. - - * runtime/ArrayPrototype.h: - -2012-11-08 Mark Lam - - 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 - - ArrayConstructor.h should have correct indentation - - Rubber stamped by Sam Weinig. - - * runtime/ArrayConstructor.h: - -2012-11-08 Filip Pizlo - - 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 - - Arguments.h should have correct indentation - - Rubber stamped by Sam Weinig. - - * runtime/Arguments.h: - -2012-11-08 Filip Pizlo - - 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 - - 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 - - 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 - - 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 - - [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 - - 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 - - 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 - - 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 ASSERT problem on MIPS diff --git a/Source/JavaScriptCore/DerivedSources.pri b/Source/JavaScriptCore/DerivedSources.pri index f9bbbf67c..03a935575 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) { +if(linux-*|win32):!equals(QT_ARCH, "arm") { #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 6c7eac9e3..d68a22b9f 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -83,8 +83,6 @@ 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 \ @@ -256,9 +254,9 @@ javascriptcore_sources += \ Source/JavaScriptCore/heap/CopiedBlock.h \ Source/JavaScriptCore/heap/CopiedSpace.cpp \ Source/JavaScriptCore/heap/CopiedSpace.h \ - Source/JavaScriptCore/heap/CopiedSpaceInlines.h \ + Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h \ Source/JavaScriptCore/heap/CopyVisitor.h \ - Source/JavaScriptCore/heap/CopyVisitorInlines.h \ + Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h \ Source/JavaScriptCore/heap/CopyVisitor.cpp \ Source/JavaScriptCore/heap/CardSet.h \ Source/JavaScriptCore/heap/ConservativeRoots.cpp \ @@ -276,7 +274,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/heap/IncrementalSweeper.cpp \ Source/JavaScriptCore/heap/SlotVisitor.cpp \ Source/JavaScriptCore/heap/SlotVisitor.h \ - Source/JavaScriptCore/heap/SlotVisitorInlines.h \ + Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h \ Source/JavaScriptCore/heap/HandleStack.cpp \ Source/JavaScriptCore/heap/HandleStack.h \ Source/JavaScriptCore/heap/HandleTypes.h \ @@ -299,7 +297,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/heap/MachineStackMarker.h \ Source/JavaScriptCore/heap/MarkStack.cpp \ Source/JavaScriptCore/heap/MarkStack.h \ - Source/JavaScriptCore/heap/MarkStackInlines.h \ + Source/JavaScriptCore/heap/MarkStackInlineMethods.h \ Source/JavaScriptCore/heap/HeapRootVisitor.h \ Source/JavaScriptCore/heap/MarkedAllocator.cpp \ Source/JavaScriptCore/heap/MarkedAllocator.h \ @@ -400,7 +398,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/jit/JIT.h \ Source/JavaScriptCore/jit/JITExceptions.cpp \ Source/JavaScriptCore/jit/JITExceptions.h \ - Source/JavaScriptCore/jit/JITInlines.h \ + Source/JavaScriptCore/jit/JITInlineMethods.h \ Source/JavaScriptCore/jit/JITOpcodes32_64.cpp \ Source/JavaScriptCore/jit/JITOpcodes.cpp \ Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp \ @@ -483,7 +481,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/BooleanObject.h \ Source/JavaScriptCore/runtime/BooleanPrototype.cpp \ Source/JavaScriptCore/runtime/BooleanPrototype.h \ - Source/JavaScriptCore/runtime/ButterflyInlines.h \ + Source/JavaScriptCore/runtime/ButterflyInlineMethods.h \ Source/JavaScriptCore/runtime/Butterfly.h \ Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h \ Source/JavaScriptCore/runtime/CallData.cpp \ @@ -531,7 +529,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/GetterSetter.h \ Source/JavaScriptCore/runtime/Identifier.cpp \ Source/JavaScriptCore/runtime/Identifier.h \ - Source/JavaScriptCore/runtime/IndexingHeaderInlines.h \ + Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h \ Source/JavaScriptCore/runtime/IndexingHeader.h \ Source/JavaScriptCore/runtime/IndexingType.cpp \ Source/JavaScriptCore/runtime/IndexingType.h \ @@ -592,7 +590,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/JSTypeInfo.h \ Source/JavaScriptCore/runtime/JSValue.cpp \ Source/JavaScriptCore/runtime/JSValue.h \ - Source/JavaScriptCore/runtime/JSValueInlines.h \ + Source/JavaScriptCore/runtime/JSValueInlineMethods.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 924261d4f..c86ca8e3d 100644 --- a/Source/JavaScriptCore/JavaScriptCore.pro +++ b/Source/JavaScriptCore/JavaScriptCore.pro @@ -7,7 +7,7 @@ TEMPLATE = subdirs CONFIG += ordered -if(linux-*|win32*) { +if(linux-*|win32*):!equals(QT_ARCH, "arm") { 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*):addStrictSubdirOrderBetween(LLIntOffsetsExtractor, derived_sources) +if(linux-*|win32*):!equals(QT_ARCH, "arm"):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 e57335015..b23100547 100755 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -54,7 +54,6 @@ 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 @@ -111,12 +110,11 @@ 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 @@ -335,7 +333,6 @@ 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 @@ -405,7 +402,6 @@ 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 0e732d187..b1567e2cd 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -538,7 +538,7 @@ > - - - - @@ -1986,7 +1978,7 @@ > JumpVector; - - JumpList() { } - - JumpList(Jump jump) - { - append(jump); - } void link(AbstractMacroAssembler* masm) { diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h index 53cb80c21..66db26acb 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h @@ -826,15 +826,11 @@ 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 4d08b70ce..ecb178e88 100644 --- a/Source/JavaScriptCore/assembler/X86Assembler.h +++ b/Source/JavaScriptCore/assembler/X86Assembler.h @@ -1475,12 +1475,6 @@ public: return m_formatter.immediateRel32(); } - AssemblerLabel jnp() - { - m_formatter.twoByteOp(jccRel32(ConditionNP)); - return m_formatter.immediateRel32(); - } - AssemblerLabel jp() { m_formatter.twoByteOp(jccRel32(ConditionP)); @@ -2320,9 +2314,6 @@ 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 deleted file mode 100644 index aa682da86..000000000 --- a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 deleted file mode 100644 index a1647fad4..000000000 --- a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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 51baf332f..5a87380fd 100644 --- a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp +++ b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp @@ -65,13 +65,6 @@ 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 5116cd36f..376684fc1 100644 --- a/Source/JavaScriptCore/bytecode/ArrayProfile.h +++ b/Source/JavaScriptCore/bytecode/ArrayProfile.h @@ -45,20 +45,15 @@ typedef unsigned ArrayModes; #define ALL_NON_ARRAY_ARRAY_MODES \ (asArrayModes(NonArray) \ - | asArrayModes(NonArrayWithInt32) \ - | asArrayModes(NonArrayWithDouble) \ - | asArrayModes(NonArrayWithContiguous) \ - | asArrayModes(NonArrayWithArrayStorage) \ - | asArrayModes(NonArrayWithSlowPutArrayStorage)) + | asArrayModes(NonArrayWithContiguous) \ + | asArrayModes(NonArrayWithArrayStorage) \ + | asArrayModes(NonArrayWithSlowPutArrayStorage)) #define ALL_ARRAY_ARRAY_MODES \ (asArrayModes(ArrayClass) \ - | asArrayModes(ArrayWithUndecided) \ - | asArrayModes(ArrayWithInt32) \ - | asArrayModes(ArrayWithDouble) \ - | asArrayModes(ArrayWithContiguous) \ - | asArrayModes(ArrayWithArrayStorage) \ - | asArrayModes(ArrayWithSlowPutArrayStorage)) + | asArrayModes(ArrayWithContiguous) \ + | asArrayModes(ArrayWithArrayStorage) \ + | asArrayModes(ArrayWithSlowPutArrayStorage)) #define ALL_ARRAY_MODES (ALL_NON_ARRAY_ARRAY_MODES | ALL_ARRAY_ARRAY_MODES) @@ -84,36 +79,6 @@ 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() @@ -163,7 +128,6 @@ 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 3f79967df..8cba4463d 100644 --- a/Source/JavaScriptCore/bytecode/ByValInfo.h +++ b/Source/JavaScriptCore/bytecode/ByValInfo.h @@ -39,8 +39,6 @@ namespace JSC { enum JITArrayMode { - JITInt32, - JITDouble, JITContiguous, JITArrayStorage, JITInt8Array, @@ -57,8 +55,6 @@ 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; @@ -81,10 +77,6 @@ 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 83833c6ec..5686d5d2c 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 "SlotVisitorInlines.h" +#include "SlotVisitorInlineMethods.h" #include #include #include @@ -654,7 +654,6 @@ void CodeBlock::dump(ExecState* exec, const Vector::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: { @@ -662,7 +661,6 @@ void CodeBlock::dump(ExecState* exec, const Vector::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: { @@ -671,7 +669,6 @@ void CodeBlock::dump(ExecState* exec, const Vector::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: { @@ -1749,8 +1746,6 @@ 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 @@ -1805,32 +1800,22 @@ 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]; -#endif -#if ENABLE(LLINT) - instructions[i + 4] = &m_llintCallLinkInfos[pc[i + 4].u.operand]; -#endif + // fallthrough +#if !ENABLE(LLINT) break; +#endif } - case op_construct: +#endif #if ENABLE(LLINT) + case op_construct: instructions[i + 4] = &m_llintCallLinkInfos[pc[i + 4].u.operand]; -#endif break; +#endif case op_get_by_id_out_of_line: case op_get_by_id_self: case op_get_by_id_proto: @@ -2805,28 +2790,18 @@ void CodeBlock::updateAllPredictionsAndCountLiveness( #if ENABLE(DFG_JIT) m_lazyOperandValueProfiles.computeUpdatedPredictions(operation); #endif -} - -void CodeBlock::updateAllValueProfilePredictions(OperationInProgress operation) -{ - unsigned ignoredValue1, ignoredValue2; - updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2); -} - -void CodeBlock::updateAllArrayPredictions(OperationInProgress operation) -{ + + // 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. 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) { - updateAllValueProfilePredictions(operation); - updateAllArrayPredictions(operation); + unsigned ignoredValue1, ignoredValue2; + updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2); } bool CodeBlock::shouldOptimizeNow() @@ -2842,14 +2817,12 @@ 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 (%u / %u), %lf (%u / %u)\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), numberOfLiveNonArgumentValueProfiles, numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles(), numberOfSamplesInProfiles, ValueProfile::numberOfBuckets * numberOfValueProfiles()); + dataLog("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)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 0199935bb..a28064940 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -755,13 +755,6 @@ 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 @@ -1152,13 +1145,9 @@ 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 @@ -1341,7 +1330,6 @@ namespace JSC { SegmentedVector m_valueProfiles; SegmentedVector m_rareCaseProfiles; SegmentedVector m_specialFastCaseProfiles; - SegmentedVector m_arrayAllocationProfiles; ArrayProfileVector m_arrayProfiles; unsigned m_executionEntryCount; #endif diff --git a/Source/JavaScriptCore/bytecode/DFGExitProfile.h b/Source/JavaScriptCore/bytecode/DFGExitProfile.h index 7132adfd4..60d313ad4 100644 --- a/Source/JavaScriptCore/bytecode/DFGExitProfile.h +++ b/Source/JavaScriptCore/bytecode/DFGExitProfile.h @@ -58,8 +58,6 @@ 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 50b80e03c..9fcf509f6 100644 --- a/Source/JavaScriptCore/bytecode/Instruction.h +++ b/Source/JavaScriptCore/bytecode/Instruction.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2008 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,7 +47,6 @@ 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; @@ -194,7 +193,6 @@ namespace JSC { Instruction(ValueProfile* profile) { u.profile = profile; } Instruction(ArrayProfile* profile) { u.arrayProfile = profile; } - Instruction(ArrayAllocationProfile* profile) { u.arrayAllocationProfile = profile; } Instruction(WriteBarrier* registerPointer) { u.registerPointer = registerPointer; } @@ -214,7 +212,6 @@ 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 38d314d78..8979d0b7b 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, 5) \ - macro(op_new_array_with_size, 4) \ - macro(op_new_array_buffer, 5) \ + macro(op_new_array, 4) \ + macro(op_new_array_with_size, 3) \ + macro(op_new_array_buffer, 4) \ macro(op_new_regexp, 3) \ macro(op_mov, 3) \ \ diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h index 656bc79ee..09ba9fdfa 100644 --- a/Source/JavaScriptCore/bytecode/SpeculatedType.h +++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h @@ -61,7 +61,6 @@ 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. @@ -229,16 +228,6 @@ 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; @@ -249,26 +238,11 @@ 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 e98d4de0a..8aa48404a 100644 --- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp @@ -80,6 +80,8 @@ 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); @@ -110,16 +112,12 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData { switch (specializationKind) { case CodeForCall: - if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForCall.get()) { - globalData.codeCache()->usedFunctionCode(globalData, codeBlock); - return codeBlock; - } + if (m_codeBlockForCall) + return m_codeBlockForCall.get(); break; case CodeForConstruct: - if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForConstruct.get()) { - globalData.codeCache()->usedFunctionCode(globalData, codeBlock); - return codeBlock; - } + if (m_codeBlockForConstruct) + return m_codeBlockForConstruct.get(); break; } @@ -130,11 +128,11 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData switch (specializationKind) { case CodeForCall: - m_codeBlockForCall = PassWeak(result); + m_codeBlockForCall.set(globalData, this, result); m_symbolTableForCall.set(globalData, this, result->symbolTable()); break; case CodeForConstruct: - m_codeBlockForConstruct = PassWeak(result); + m_codeBlockForConstruct.set(globalData, this, result); m_symbolTableForConstruct.set(globalData, this, result->symbolTable()); break; } @@ -173,7 +171,6 @@ 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 23937d773..bf3f5fdff 100644 --- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h +++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h @@ -36,7 +36,6 @@ #include "Nodes.h" #include "RegExp.h" #include "SpecialPointer.h" -#include "Weak.h" #include #include @@ -57,7 +56,6 @@ class UnlinkedFunctionCodeBlock; typedef unsigned UnlinkedValueProfile; typedef unsigned UnlinkedArrayProfile; -typedef unsigned UnlinkedArrayAllocationProfile; typedef unsigned UnlinkedLLIntCallLinkInfo; struct ExecutableInfo { @@ -109,7 +107,7 @@ public: FunctionExecutable* link(JSGlobalData&, const SourceCode&, size_t lineOffset, size_t sourceOffset); - void clearCodeForRecompilation() + void clearCode() { m_symbolTableForCall.clear(); m_symbolTableForConstruct.clear(); @@ -137,8 +135,8 @@ public: private: UnlinkedFunctionExecutable(JSGlobalData*, Structure*, const SourceCode&, FunctionBodyNode*); - Weak m_codeBlockForCall; - Weak m_codeBlockForConstruct; + WriteBarrier m_codeBlockForCall; + WriteBarrier m_codeBlockForConstruct; unsigned m_numCapturedVariables : 29; bool m_forceUsesArguments : 1; @@ -394,8 +392,6 @@ 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; } @@ -522,7 +518,6 @@ 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 b1b9de6c1..b11872551 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -716,15 +716,6 @@ 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) @@ -1614,7 +1605,6 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen instructions().append(dst->index()); instructions().append(constantBufferIndex); instructions().append(length); - instructions().append(newArrayAllocationProfile()); return dst; } } @@ -1632,7 +1622,6 @@ 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; } @@ -1768,14 +1757,12 @@ 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 2e7aa2035..828726dee 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -523,7 +523,6 @@ 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 7eda52dc8..b14729146 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->clearUnlinkedCodeForRecompilationIfNotCompiling(); + executable->clearUnlinkedCodeIfNotCompiling(); 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 02e578b29..e518c24a8 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) +bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDirectionPtr) { ASSERT(m_block); @@ -167,7 +167,6 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode) block->cfaFoundConstants = m_foundConstants; block->cfaDidFinish = m_isValid; - block->cfaBranchDirection = m_branchDirection; if (!m_isValid) { reset(); @@ -196,8 +195,12 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode) ASSERT(mergeMode != DontMerge || !changed); + BranchDirection branchDirection = m_branchDirection; + if (branchDirectionPtr) + *branchDirectionPtr = branchDirection; + #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog(" Branch direction = %s\n", branchDirectionToString(m_branchDirection)); + dataLog(" Branch direction = %s\n", branchDirectionToString(branchDirection)); #endif reset(); @@ -205,7 +208,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode) if (mergeMode != MergeToSuccessors) return changed; - return mergeToSuccessors(m_graph, block); + return mergeToSuccessors(m_graph, block, branchDirection); } void AbstractState::reset() @@ -421,10 +424,7 @@ bool AbstractState::execute(unsigned indexInBlock) break; } speculateNumberUnary(node); - if (isInt32Speculation(forNode(node.child1()).m_type)) - forNode(nodeIndex).set(SpecDoubleReal); - else - forNode(nodeIndex).set(SpecDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -448,13 +448,9 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(nodeIndex).set(SpecInt32); break; } - if (Node::shouldSpeculateNumberExpectingDefined(m_graph[node.child1()], m_graph[node.child2()])) { + if (Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()])) { speculateNumberBinary(node); - if (isRealNumberSpeculation(forNode(node.child1()).m_type) - && isRealNumberSpeculation(forNode(node.child2()).m_type)) - forNode(nodeIndex).set(SpecDoubleReal); - else - forNode(nodeIndex).set(SpecDouble); + forNode(nodeIndex).set(SpecDouble); break; } if (node.op() == ValueAdd) { @@ -526,11 +522,7 @@ bool AbstractState::execute(unsigned indexInBlock) break; } speculateNumberBinary(node); - if (isRealNumberSpeculation(forNode(node.child1()).m_type) - || isRealNumberSpeculation(forNode(node.child2()).m_type)) - forNode(nodeIndex).set(SpecDoubleReal); - else - forNode(nodeIndex).set(SpecDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -568,7 +560,7 @@ bool AbstractState::execute(unsigned indexInBlock) break; } } - if (Node::shouldSpeculateIntegerForArithmetic( + if (Node::shouldSpeculateInteger( m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) { speculateInt32Binary(node, true); // forcing can-exit, which is a bit on the conservative side. @@ -588,7 +580,7 @@ bool AbstractState::execute(unsigned indexInBlock) node.setCanExit(false); break; } - if (m_graph[node.child1()].shouldSpeculateIntegerForArithmetic() + if (m_graph[node.child1()].shouldSpeculateInteger() && node.canSpeculateInteger()) { speculateInt32Unary(node, true); forNode(nodeIndex).set(SpecInt32); @@ -613,22 +605,12 @@ 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); @@ -696,13 +678,12 @@ 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)); @@ -724,20 +705,11 @@ bool AbstractState::execute(unsigned indexInBlock) constantWasSet = 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; + if (constantWasSet) { + m_foundConstants = true; + node.setCanExit(false); + break; + } } forNode(nodeIndex).set(SpecBoolean); @@ -870,7 +842,6 @@ 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: @@ -888,22 +859,6 @@ 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: @@ -971,20 +926,6 @@ 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); @@ -1077,16 +1018,6 @@ 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; @@ -1112,7 +1043,6 @@ 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()); @@ -1123,14 +1053,6 @@ 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 @@ -1200,13 +1122,13 @@ bool AbstractState::execute(unsigned indexInBlock) case NewArray: node.setCanExit(true); - forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())); + forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure()); m_haveStructures = true; break; case NewArrayBuffer: node.setCanExit(true); - forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())); + forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure()); m_haveStructures = true; break; @@ -1462,11 +1384,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: @@ -1800,7 +1722,7 @@ inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to) } inline bool AbstractState::mergeToSuccessors( - Graph& graph, BasicBlock* basicBlock) + Graph& graph, BasicBlock* basicBlock, BranchDirection branchDirection) { Node& terminal = graph[basicBlock->last()]; @@ -1808,7 +1730,7 @@ inline bool AbstractState::mergeToSuccessors( switch (terminal.op()) { case Jump: { - ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection); + ASSERT(branchDirection == InvalidBranchDirection); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog(" Merging to block #%u.\n", terminal.takenBlockIndex()); #endif @@ -1816,17 +1738,17 @@ inline bool AbstractState::mergeToSuccessors( } case Branch: { - ASSERT(basicBlock->cfaBranchDirection != InvalidBranchDirection); + ASSERT(branchDirection != InvalidBranchDirection); bool changed = false; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog(" Merging to block #%u.\n", terminal.takenBlockIndex()); #endif - if (basicBlock->cfaBranchDirection != TakeFalse) + if (branchDirection != 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 (basicBlock->cfaBranchDirection != TakeTrue) + if (branchDirection != TakeTrue) changed |= merge(basicBlock, graph.m_blocks[terminal.notTakenBlockIndex()].get()); return changed; } @@ -1834,7 +1756,7 @@ inline bool AbstractState::mergeToSuccessors( case Return: case Throw: case ThrowReferenceError: - ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection); + ASSERT(branchDirection == InvalidBranchDirection); return false; default: diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h index 0e33140c0..ec1a06231 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.h +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,7 +31,6 @@ #if ENABLE(DFG_JIT) #include "DFGAbstractValue.h" -#include "DFGBranchDirection.h" #include "DFGGraph.h" #include "DFGNode.h" #include @@ -93,6 +92,36 @@ 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(); @@ -145,7 +174,11 @@ 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. - bool endBasicBlock(MergeMode); + // + // 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); // Reset the AbstractState. This throws away any results, and at this point // you can safely call beginBasicBlock() on any basic block. @@ -178,8 +211,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*); - + bool mergeToSuccessors(Graph&, BasicBlock*, BranchDirection); + void dump(FILE* out); private: diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp index 0d15b9a30..699902a16 100644 --- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp +++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp @@ -34,46 +34,19 @@ namespace JSC { namespace DFG { ArrayMode ArrayMode::fromObserved(ArrayProfile* profile, Array::Action action, bool makeSafe) { - ArrayModes observed = profile->observedArrayModes(); - switch (observed) { + switch (profile->observedArrayModes()) { case 0: return ArrayMode(Array::Unprofiled); case asArrayModes(NonArray): if (action == Array::Write && !profile->mayInterceptIndexedAccesses()) - return ArrayMode(Array::Undecided, Array::NonArray, Array::OutOfBounds, Array::Convert); + 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::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): @@ -89,39 +62,36 @@ 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: - 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); + // 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); } } -ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, SpeculatedType value) const +ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index) const { if (!base || !index) { // It can be that we had a legitimate arrayMode but no incoming predictions. That'll @@ -134,85 +104,49 @@ ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, Speculate if (!isInt32Speculation(index) || !isCellSpeculation(base)) return ArrayMode(Array::Generic); - switch (type()) { - case Array::Unprofiled: + 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. return ArrayMode(Array::ForceExit); - - 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; - } -} - -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; + + if (type() != Array::SelectUsingPredictions) + 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) const @@ -227,17 +161,31 @@ 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: - return alreadyChecked(value, ContiguousShape); + 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()); case Array::ArrayStorage: - return alreadyChecked(value, ArrayStorageShape); + 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()); case Array::SlowPutArrayStorage: if (isJSArray()) { @@ -284,7 +232,6 @@ bool ArrayMode::alreadyChecked(AbstractValue& value) const case Array::SelectUsingPredictions: case Array::Unprofiled: - case Array::Undecided: break; } @@ -305,12 +252,6 @@ 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 206d689f2..615965c92 100644 --- a/Source/JavaScriptCore/dfg/DFGArrayMode.h +++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h @@ -52,10 +52,7 @@ 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, @@ -84,6 +81,7 @@ enum Speculation { ToHole, OutOfBounds }; + enum Conversion { AsIs, Convert @@ -171,17 +169,7 @@ public: return ArrayMode(type(), myArrayClass, mySpeculation, conversion()); } - 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; + ArrayMode refine(SpeculatedType base, SpeculatedType index) const; bool alreadyChecked(AbstractValue&) const; @@ -190,8 +178,6 @@ public: bool usesButterfly() const { switch (type()) { - case Array::Int32: - case Array::Double: case Array::Contiguous: case Array::ArrayStorage: case Array::SlowPutArrayStorage: @@ -277,7 +263,6 @@ public: case Array::Unprofiled: case Array::ForceExit: case Array::Generic: - case Array::Undecided: return false; default: return true; @@ -292,8 +277,6 @@ public: case Array::ForceExit: case Array::Generic: return false; - case Array::Int32: - case Array::Double: case Array::Contiguous: case Array::ArrayStorage: case Array::SlowPutArrayStorage: @@ -326,10 +309,6 @@ 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: @@ -375,8 +354,6 @@ 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 6f348f2e1..441e2e75e 100644 --- a/Source/JavaScriptCore/dfg/DFGBasicBlock.h +++ b/Source/JavaScriptCore/dfg/DFGBasicBlock.h @@ -29,7 +29,6 @@ #if ENABLE(DFG_JIT) #include "DFGAbstractValue.h" -#include "DFGBranchDirection.h" #include "DFGNode.h" #include "Operands.h" #include @@ -47,7 +46,6 @@ struct BasicBlock : Vector { , cfaShouldRevisit(false) , cfaFoundConstants(false) , cfaDidFinish(true) - , cfaBranchDirection(InvalidBranchDirection) #if !ASSERT_DISABLED , isLinked(false) #endif @@ -107,7 +105,6 @@ struct BasicBlock : Vector { 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 deleted file mode 100644 index 8bbe3c635..000000000 --- a/Source/JavaScriptCore/dfg/DFGBranchDirection.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 - -#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 142b8ab95..70aa2b637 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -905,15 +905,10 @@ private: return getPrediction(m_graph.size(), m_currentProfilingIndex); } - ArrayMode getArrayMode(ArrayProfile* profile, Array::Action action) - { - profile->computeUpdatedPrediction(m_inlineStackTop->m_codeBlock); - return ArrayMode::fromObserved(profile, action, false); - } - ArrayMode getArrayMode(ArrayProfile* profile) { - return getArrayMode(profile, Array::Read); + profile->computeUpdatedPrediction(m_inlineStackTop->m_codeBlock); + return ArrayMode::fromObserved(profile, Array::Read, false); } ArrayMode getArrayModeAndEmitChecks(ArrayProfile* profile, Array::Action action, NodeIndex base) @@ -1654,12 +1649,7 @@ 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))); @@ -1679,11 +1669,7 @@ 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))); @@ -1768,7 +1754,7 @@ bool ByteCodeParser::handleConstantInternalFunction( if (argumentCountIncludingThis == 2) { setIntrinsicResult( usesResult, resultOperand, - addToGraph(NewArrayWithSize, OpInfo(ArrayWithUndecided), get(registerOffset + argumentToOperand(1)))); + addToGraph(NewArrayWithSize, get(registerOffset + argumentToOperand(1)))); return true; } @@ -1776,7 +1762,7 @@ bool ByteCodeParser::handleConstantInternalFunction( addVarArgChild(get(registerOffset + argumentToOperand(i))); setIntrinsicResult( usesResult, resultOperand, - addToGraph(Node::VarArg, NewArray, OpInfo(ArrayWithUndecided), OpInfo(0))); + addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0))); return true; } @@ -2136,37 +2122,24 @@ 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(profile->selectIndexingType()), OpInfo(0))); + set(currentInstruction[1].u.operand, addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0))); NEXT_OPCODE(op_new_array); } case op_new_array_with_size: { int lengthOperand = currentInstruction[2].u.operand; - ArrayAllocationProfile* profile = currentInstruction[3].u.arrayAllocationProfile; - set(currentInstruction[1].u.operand, addToGraph(NewArrayWithSize, OpInfo(profile->selectIndexingType()), get(lengthOperand))); + set(currentInstruction[1].u.operand, addToGraph(NewArrayWithSize, 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 308dde5a6..a2570b7ea 100644 --- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h @@ -210,15 +210,6 @@ 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(); @@ -277,16 +268,6 @@ 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(); @@ -336,23 +317,6 @@ 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. @@ -499,20 +463,6 @@ public: { setupTwoStubArgs(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) @@ -546,21 +496,6 @@ 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." @@ -700,13 +635,6 @@ public: move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); } - ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, GPRReg arg3) - { - setupTwoStubArgs(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); @@ -795,12 +723,6 @@ 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 e3827d8ad..e0d973992 100644 --- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp @@ -99,8 +99,9 @@ public: case Branch: { // Branch on constant -> jettison the not-taken block and merge. - if (isKnownDirection(block->cfaBranchDirection)) { - bool condition = branchCondition(block->cfaBranchDirection); + 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()); BasicBlock* targetBlock = m_graph.m_blocks[ m_graph.successorForCondition(block, condition)].get(); if (targetBlock->m_predecessors.size() == 1) { @@ -729,7 +730,6 @@ 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 03713b6c5..46d5f44cb 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 = m_plans.size(); i--;) + for (unsigned i = 0; 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 = m_plans.size(); i--;) + for (unsigned i = 0; 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 621d6e96a..5a76aa8df 100644 --- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp @@ -145,30 +145,7 @@ 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; } @@ -259,7 +236,7 @@ private: case ValueAdd: { if (m_graph.addShouldSpeculateInteger(node)) break; - if (!Node::shouldSpeculateNumberExpectingDefined(m_graph[node.child1()], m_graph[node.child2()])) + if (!Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()])) break; fixDoubleEdge(0); fixDoubleEdge(1); @@ -285,7 +262,7 @@ private: case ArithMin: case ArithMax: case ArithMod: { - if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) + if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) break; fixDoubleEdge(0); @@ -302,7 +279,7 @@ private: } case ArithDiv: { - if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) + if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) { if (isX86()) break; @@ -330,7 +307,7 @@ private: } case ArithAbs: { - if (m_graph[node.child1()].shouldSpeculateIntegerForArithmetic() + if (m_graph[node.child1()].shouldSpeculateInteger() && node.canSpeculateInteger()) break; fixDoubleEdge(0); @@ -351,17 +328,13 @@ private: node.setArrayMode( node.arrayMode().refine( m_graph[child1].prediction(), - m_graph[child2].prediction(), - m_graph[child3].prediction())); + m_graph[child2].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: @@ -382,19 +355,6 @@ 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; } @@ -432,17 +392,15 @@ 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->originalArrayStructureForIndexingType(ArrayWithContiguous); + structure = globalObject->arrayStructure(); + if (structure->indexingType() != ArrayWithContiguous) + structure = 0; break; case Array::ArrayStorage: - structure = globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage); + structure = globalObject->arrayStructureWithArrayStorage(); + if (structure->indexingType() != ArrayWithArrayStorage) + structure = 0; break; default: break; diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp index 38079f020..8e8817f81 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.cpp +++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp @@ -287,11 +287,6 @@ 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 4de2e0e26..9fbb2df07 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::shouldSpeculateIntegerExpectingDefined(left, right) && add.canSpeculateInteger(); + return Node::shouldSpeculateInteger(left, right) && add.canSpeculateInteger(); } bool mulShouldSpeculateInteger(Node& mul) @@ -235,13 +235,13 @@ public: if (right.hasConstant()) return mulImmediateShouldSpeculateInteger(mul, left, right); - return Node::shouldSpeculateIntegerForArithmetic(left, right) && mul.canSpeculateInteger() && !nodeMayOverflow(mul.arithNodeFlags()); + return Node::shouldSpeculateInteger(left, right) && mul.canSpeculateInteger() && !nodeMayOverflow(mul.arithNodeFlags()); } bool negateShouldSpeculateInteger(Node& negate) { ASSERT(negate.op() == ArithNegate); - return at(negate.child1()).shouldSpeculateIntegerForArithmetic() && negate.canSpeculateInteger(); + return at(negate.child1()).shouldSpeculateInteger() && negate.canSpeculateInteger(); } bool addShouldSpeculateInteger(NodeIndex nodeIndex) @@ -493,8 +493,6 @@ 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(); @@ -714,7 +712,7 @@ private: if (!immediateValue.isNumber()) return false; - if (!variable.shouldSpeculateIntegerExpectingDefined()) + if (!variable.shouldSpeculateInteger()) return false; if (immediateValue.isInt32()) @@ -736,7 +734,7 @@ private: if (!immediateValue.isInt32()) return false; - if (!variable.shouldSpeculateIntegerForArithmetic()) + if (!variable.shouldSpeculateInteger()) return false; int32_t intImmediate = immediateValue.asInt32(); diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index bff7fe65f..e66629ec4 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -62,7 +62,6 @@ struct StructureTransitionData { struct NewArrayBufferData { unsigned startConstant; unsigned numConstants; - IndexingType indexingType; }; // This type used in passing an immediate argument to Node constructor; @@ -434,32 +433,6 @@ 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; @@ -949,36 +922,16 @@ 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()); @@ -1084,31 +1037,11 @@ 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 8356d22f9..0e45e230c 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -27,9 +27,9 @@ #include "DFGOperations.h" #include "Arguments.h" -#include "ButterflyInlines.h" +#include "ButterflyInlineMethods.h" #include "CodeBlock.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.h" #include "DFGOSRExit.h" #include "DFGRepatch.h" #include "DFGThunks.h" @@ -580,40 +580,6 @@ 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(); @@ -623,15 +589,6 @@ 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(); @@ -1370,36 +1327,30 @@ char* DFG_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState* return reinterpret_cast(result); } -char* DFG_OPERATION operationEnsureInt32(ExecState* exec, JSObject* object) +char* DFG_OPERATION operationEnsureContiguous(ExecState* exec, JSObject* object) { JSGlobalData& globalData = exec->globalData(); NativeCallFrameTracer tracer(&globalData, exec); - return reinterpret_cast(object->ensureInt32(globalData)); + return reinterpret_cast(object->ensureContiguous(globalData)); } -char* DFG_OPERATION operationEnsureDouble(ExecState* exec, JSObject* object) +char* DFG_OPERATION operationEnsureArrayStorage(ExecState* exec, JSObject* object) { JSGlobalData& globalData = exec->globalData(); NativeCallFrameTracer tracer(&globalData, exec); - - return reinterpret_cast(object->ensureDouble(globalData)); -} -char* DFG_OPERATION operationEnsureContiguous(ExecState* exec, JSObject* object) -{ - JSGlobalData& globalData = exec->globalData(); - NativeCallFrameTracer tracer(&globalData, exec); - - return reinterpret_cast(object->ensureContiguous(globalData)); + return reinterpret_cast(object->ensureArrayStorage(globalData)); } -char* DFG_OPERATION operationEnsureArrayStorage(ExecState* exec, JSObject* object) +char* DFG_OPERATION operationEnsureContiguousOrArrayStorage(ExecState* exec, JSObject* object, int32_t index) { JSGlobalData& globalData = exec->globalData(); NativeCallFrameTracer tracer(&globalData, exec); - return reinterpret_cast(object->ensureArrayStorage(globalData)); + if (static_cast(index) >= MIN_SPARSE_ARRAY_INDEX) + return reinterpret_cast(object->ensureArrayStorage(globalData)); + return reinterpret_cast(object->ensureIndexedStorage(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 b99c214e9..8d2beacec 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.h +++ b/Source/JavaScriptCore/dfg/DFGOperations.h @@ -64,7 +64,6 @@ 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*); @@ -93,7 +92,6 @@ 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*); @@ -150,10 +148,7 @@ 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; @@ -200,10 +195,9 @@ 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 b5fde4eee..3e8ead5c6 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -225,6 +225,24 @@ 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); @@ -240,7 +258,7 @@ private: SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)) { + if (isNumberSpeculation(left) && isNumberSpeculation(right)) { if (m_graph.addShouldSpeculateInteger(node)) changed |= mergePrediction(SpecInt32); else @@ -315,7 +333,7 @@ private: SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) + if (isInt32Speculation(mergeSpeculations(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(SpecInt32); else @@ -355,7 +373,7 @@ private: SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) + if (isInt32Speculation(mergeSpeculations(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(SpecInt32); else @@ -364,7 +382,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, ArithDiv always checks for overflow + // can change the outcome. So, ArithMul always checks for overflow // no matter what, and always forces its inputs to check as well. flags |= NodeUsedAsNumber | NodeNeedsNegZero; @@ -373,24 +391,6 @@ 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,11 +399,10 @@ private: case ArithAbs: { SpeculatedType child = m_graph[node.child1()].prediction(); - if (isInt32SpeculationForArithmetic(child) - && nodeCanSpeculateInteger(node.arithNodeFlags())) - changed |= mergePrediction(SpecInt32); + if (nodeCanSpeculateInteger(node.arithNodeFlags())) + changed |= mergePrediction(child); else - changed |= mergePrediction(speculatedDoubleTypeForPrediction(child)); + changed |= setPrediction(speculatedDoubleTypeForPrediction(child)); flags &= ~NodeNeedsNegZero; changed |= m_graph[node.child1()].mergeFlags(flags); @@ -777,7 +776,7 @@ private: DoubleBallot ballot; - if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right) + if (isNumberSpeculation(left) && isNumberSpeculation(right) && !m_graph.addShouldSpeculateInteger(node)) ballot = VoteDouble; else @@ -815,7 +814,7 @@ private: DoubleBallot ballot; if (isNumberSpeculation(left) && isNumberSpeculation(right) - && !(Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child1()]) + && !(Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child1()]) && node.canSpeculateInteger())) ballot = VoteDouble; else @@ -828,7 +827,7 @@ private: case ArithAbs: DoubleBallot ballot; - if (!(m_graph[node.child1()].shouldSpeculateIntegerForArithmetic() + if (!(m_graph[node.child1()].shouldSpeculateInteger() && node.canSpeculateInteger())) ballot = VoteDouble; else @@ -850,24 +849,6 @@ 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 829bc14ff..6bedd6d68 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(hasUndecided(structure->indexingType()) || hasInt32(structure->indexingType()) || hasDouble(structure->indexingType()) || hasContiguous(structure->indexingType())); + ASSERT(hasContiguous(structure->indexingType())); GPRTemporary scratch(this); GPRReg scratchGPR = scratch.gpr(); @@ -67,7 +67,6 @@ 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); @@ -80,21 +79,6 @@ 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(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. :-/ @@ -359,31 +343,24 @@ 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::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::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::ArrayStorage: case Array::SlowPutArrayStorage: { if (arrayMode.isJSArray()) { @@ -460,8 +437,6 @@ 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: { @@ -553,30 +528,16 @@ 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 (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; - } + if (node.arrayMode().type() == Array::Contiguous && propertyReg != InvalidGPRReg) { + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branch32( + MacroAssembler::AboveOrEqual, propertyReg, TrustedImm32(MIN_SPARSE_ARRAY_INDEX))); } // 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; @@ -1836,85 +1797,6 @@ 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()); @@ -2881,7 +2763,7 @@ void SpeculativeJIT::compileAdd(Node& node) return; } - if (Node::shouldSpeculateNumberExpectingDefined(at(node.child1()), at(node.child2()))) { + if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) { SpeculateDoubleOperand op1(this, node.child1()); SpeculateDoubleOperand op2(this, node.child2()); FPRTemporary result(this, op1, op2); @@ -3119,7 +3001,7 @@ void SpeculativeJIT::compileIntegerArithDivForX86(Node& node) void SpeculativeJIT::compileArithMod(Node& node) { - if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2())) + if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { compileSoftModulo(node); return; @@ -3454,8 +3336,6 @@ 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 059d3a6c6..446ea7dbe 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -1308,11 +1308,6 @@ 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); @@ -1458,11 +1453,6 @@ 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); @@ -1671,21 +1661,11 @@ 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); @@ -1839,21 +1819,11 @@ 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)); @@ -2300,11 +2270,6 @@ public: void compileAllocatePropertyStorage(Node&); void compileReallocatePropertyStorage(Node&); -#if USE(JSVALUE32_64) - template - 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(); @@ -2450,7 +2415,6 @@ 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); @@ -2991,11 +2955,6 @@ public: m_gprOrInvalid = m_jit->fillSpeculateInt(index(), m_format); return m_gprOrInvalid; } - - void use() - { - m_jit->use(m_index); - } private: SpeculativeJIT* m_jit; @@ -3076,11 +3035,6 @@ 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 694f1452e..65fdf5593 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -2046,69 +2046,6 @@ void SpeculativeJIT::emitBranch(Node& node) } } -template -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(); @@ -2429,8 +2366,7 @@ void SpeculativeJIT::compile(Node& node) break; case ArithDiv: { - if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2())) - && node.canSpeculateInteger()) { + if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { #if CPU(X86) compileIntegerArithDivForX86(node); #else // CPU(X86) -> so non-X86 code follows @@ -2457,8 +2393,7 @@ void SpeculativeJIT::compile(Node& node) } case ArithAbs: { - if (at(node.child1()).shouldSpeculateIntegerForArithmetic() - && node.canSpeculateInteger()) { + if (at(node.child1()).shouldSpeculateInteger() && node.canSpeculateInteger()) { SpeculateIntegerOperand op1(this, node.child1()); GPRTemporary result(this, op1); GPRTemporary scratch(this); @@ -2482,8 +2417,7 @@ void SpeculativeJIT::compile(Node& node) case ArithMin: case ArithMax: { - if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2())) - && node.canSpeculateInteger()) { + if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { SpeculateStrictInt32Operand op1(this, node.child1()); SpeculateStrictInt32Operand op2(this, node.child2()); GPRTemporary result(this, op1); @@ -2633,7 +2567,6 @@ 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()); @@ -2647,20 +2580,8 @@ void SpeculativeJIT::compile(Node& node) speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); - 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); + GPRTemporary resultPayload(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()); @@ -2700,60 +2621,6 @@ 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()) { @@ -2904,17 +2771,6 @@ 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); @@ -2928,14 +2784,61 @@ 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; + } - compileContiguousPutByVal(node, base, property, value, valuePayloadReg, valueTagReg); - break; - } - case Array::Double: { - compileDoublePutByVal(node, base, property); + 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); break; } + case Array::ArrayStorage: case Array::SlowPutArrayStorage: { JSValueOperand value(this, child3); @@ -3125,47 +3028,24 @@ 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))); @@ -3184,45 +3064,7 @@ 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. @@ -3265,7 +3107,6 @@ 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); @@ -3299,44 +3140,6 @@ 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(); @@ -3555,17 +3358,11 @@ void SpeculativeJIT::compile(Node& node) case NewArray: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) { + if (!globalObject->isHavingABadTime()) { globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); - Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()); - ASSERT(structure->indexingType() == node.indexingType()); - ASSERT( - hasUndecided(structure->indexingType()) - || hasInt32(structure->indexingType()) - || hasDouble(structure->indexingType()) - || hasContiguous(structure->indexingType())); - + ASSERT(hasContiguous(globalObject->arrayStructure()->indexingType())); + unsigned numElements = node.numChildren(); GPRTemporary result(this); @@ -3574,52 +3371,17 @@ void SpeculativeJIT::compile(Node& node) GPRReg resultGPR = result.gpr(); GPRReg storageGPR = storage.gpr(); - emitAllocateJSArray(structure, resultGPR, storageGPR, numElements); + emitAllocateJSArray(globalObject->arrayStructure(), 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) { - 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; - } + 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))); } // Yuck, we should *really* have a way of also returning the storageGPR. But @@ -3637,7 +3399,7 @@ void SpeculativeJIT::compile(Node& node) flushRegisters(); GPRResult result(this); callOperation( - operationNewEmptyArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())); + operationNewEmptyArray, result.gpr(), globalObject->arrayStructure()); cellResult(result.gpr(), m_compileIndex); break; } @@ -3647,61 +3409,13 @@ void SpeculativeJIT::compile(Node& node) EncodedJSValue* buffer = scratchBuffer ? static_cast(scratchBuffer->dataBuffer()) : 0; for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++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); - 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(buffer + operandIdx)); - break; - } - case ALL_INT32_INDEXING_TYPES: { - SpeculateIntegerOperand operand(this, use); - GPRReg opGPR = operand.gpr(); - m_jit.store32(TrustedImm32(JSValue::Int32Tag), reinterpret_cast(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); - m_jit.store32(opGPR, reinterpret_cast(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(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); - m_jit.store32(opPayloadGPR, reinterpret_cast(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; + 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(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); + m_jit.store32(opPayloadGPR, reinterpret_cast(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); } flushRegisters(); @@ -3717,8 +3431,8 @@ void SpeculativeJIT::compile(Node& node) GPRResult result(this); callOperation( - operationNewArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), - static_cast(buffer), node.numChildren()); + operationNewArray, result.gpr(), globalObject->arrayStructure(), + static_cast(buffer), node.numChildren()); if (scratchSize) { GPRTemporary scratch(this); @@ -3757,30 +3471,17 @@ void SpeculativeJIT::compile(Node& node) emitAllocateBasicStorage(resultGPR, storageGPR)); m_jit.subPtr(scratchGPR, storageGPR); emitAllocateBasicJSObject( - TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), resultGPR, scratchGPR, + TrustedImmPtr(globalObject->arrayStructure()), 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->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), - globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage), + globalObject->arrayStructure(), + globalObject->arrayStructureWithArrayStorage(), sizeGPR))); cellResult(resultGPR, m_compileIndex); @@ -3791,24 +3492,15 @@ 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, resultGPR, structureGPR, sizeGPR); - cellResult(resultGPR, m_compileIndex); + operationNewArrayWithSize, result.gpr(), globalObject->arrayStructure(), sizeGPR); + cellResult(result.gpr(), m_compileIndex); break; } case NewArrayBuffer: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - IndexingType indexingType = node.indexingType(); - if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) { + if (!globalObject->isHavingABadTime()) { globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); unsigned numElements = node.numConstants(); @@ -3819,25 +3511,12 @@ void SpeculativeJIT::compile(Node& node) GPRReg resultGPR = result.gpr(); GPRReg storageGPR = storage.gpr(); - emitAllocateJSArray(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), resultGPR, storageGPR, numElements); + emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements); - 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(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)); - } + int32_t* data = bitwise_cast(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); @@ -3847,7 +3526,7 @@ void SpeculativeJIT::compile(Node& node) flushRegisters(); GPRResult result(this); - callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), node.startConstant(), node.numConstants()); + callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructure(), 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 ecd823e7b..6c066c388 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -2403,8 +2403,7 @@ void SpeculativeJIT::compile(Node& node) break; case ArithDiv: { - if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2())) - && node.canSpeculateInteger()) { + if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { compileIntegerArithDivForX86(node); break; } @@ -2427,8 +2426,7 @@ void SpeculativeJIT::compile(Node& node) } case ArithAbs: { - if (at(node.child1()).shouldSpeculateIntegerForArithmetic() - && node.canSpeculateInteger()) { + if (at(node.child1()).shouldSpeculateInteger() && node.canSpeculateInteger()) { SpeculateIntegerOperand op1(this, node.child1()); GPRTemporary result(this); GPRTemporary scratch(this); @@ -2452,8 +2450,7 @@ void SpeculativeJIT::compile(Node& node) case ArithMin: case ArithMax: { - if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2())) - && node.canSpeculateInteger()) { + if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) { SpeculateStrictInt32Operand op1(this, node.child1()); SpeculateStrictInt32Operand op2(this, node.child2()); GPRTemporary result(this, op1); @@ -2601,7 +2598,6 @@ 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()); @@ -2618,7 +2614,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, node.arrayMode().type() == Array::Int32 ? DataFormatJSInteger : DataFormatJS); + jsValueResult(result.gpr(), m_compileIndex); break; } @@ -2651,60 +2647,6 @@ 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()) { @@ -2847,7 +2789,6 @@ void SpeculativeJIT::compile(Node& node) GPRReg propertyReg = property.gpr(); switch (arrayMode.type()) { - case Array::Int32: case Array::Contiguous: { JSValueOperand value(this, child3); @@ -2855,15 +2796,8 @@ 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 (arrayMode.type() == Array::Contiguous && Heap::isWriteBarrierEnabled()) { + if (Heap::isWriteBarrierEnabled()) { GPRTemporary scratch(this); writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratch.gpr()); } @@ -2923,11 +2857,6 @@ void SpeculativeJIT::compile(Node& node) break; } - case Array::Double: { - compileDoublePutByVal(node, base, property); - break; - } - case Array::ArrayStorage: case Array::SlowPutArrayStorage: { JSValueOperand value(this, child3); @@ -3152,31 +3081,23 @@ 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)); @@ -3193,43 +3114,7 @@ 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. @@ -3267,17 +3152,13 @@ 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); @@ -3286,27 +3167,14 @@ void SpeculativeJIT::compile(Node& node) m_jit.sub32(TrustedImm32(1), storageLengthGPR); m_jit.store32( storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); - 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( + 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)); - slowCase = m_jit.branchTest64(MacroAssembler::Zero, valueGPR); - } + MacroAssembler::Jump slowCase = m_jit.branchTest64(MacroAssembler::Zero, valueGPR); addSlowPathGenerator( slowPathMove( @@ -3316,7 +3184,6 @@ 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; } @@ -3471,16 +3338,10 @@ void SpeculativeJIT::compile(Node& node) case NewArray: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) { + if (!globalObject->isHavingABadTime()) { globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); - Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()); - ASSERT(structure->indexingType() == node.indexingType()); - ASSERT( - hasUndecided(structure->indexingType()) - || hasInt32(structure->indexingType()) - || hasDouble(structure->indexingType()) - || hasContiguous(structure->indexingType())); + ASSERT(hasContiguous(globalObject->arrayStructure()->indexingType())); unsigned numElements = node.numChildren(); @@ -3490,50 +3351,15 @@ void SpeculativeJIT::compile(Node& node) GPRReg resultGPR = result.gpr(); GPRReg storageGPR = storage.gpr(); - emitAllocateJSArray(structure, resultGPR, storageGPR, numElements); + emitAllocateJSArray(globalObject->arrayStructure(), 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) { - 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; - } + 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)); } // Yuck, we should *really* have a way of also returning the storageGPR. But @@ -3550,7 +3376,7 @@ void SpeculativeJIT::compile(Node& node) if (!node.numChildren()) { flushRegisters(); GPRResult result(this); - callOperation(operationNewEmptyArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())); + callOperation(operationNewEmptyArray, result.gpr(), globalObject->arrayStructure()); cellResult(result.gpr(), m_compileIndex); break; } @@ -3560,65 +3386,11 @@ void SpeculativeJIT::compile(Node& node) EncodedJSValue* buffer = scratchBuffer ? static_cast(scratchBuffer->dataBuffer()) : 0; for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++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; + JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]); + GPRReg opGPR = operand.gpr(); + operand.use(); + + m_jit.store64(opGPR, buffer + operandIdx); } flushRegisters(); @@ -3634,7 +3406,7 @@ void SpeculativeJIT::compile(Node& node) GPRResult result(this); callOperation( - operationNewArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), + operationNewArray, result.gpr(), globalObject->arrayStructure(), static_cast(buffer), node.numChildren()); if (scratchSize) { @@ -3650,26 +3422,18 @@ void SpeculativeJIT::compile(Node& node) case NewArrayWithSize: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) { + if (!globalObject->isHavingABadTime()) { 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))); @@ -3682,28 +3446,17 @@ void SpeculativeJIT::compile(Node& node) emitAllocateBasicStorage(resultGPR, storageGPR)); m_jit.subPtr(scratchGPR, storageGPR); emitAllocateBasicJSObject( - TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), resultGPR, scratchGPR, + TrustedImmPtr(globalObject->arrayStructure()), 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(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->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), - globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage), + globalObject->arrayStructure(), + globalObject->arrayStructureWithArrayStorage(), sizeGPR))); cellResult(resultGPR, m_compileIndex); @@ -3717,10 +3470,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->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), structureGPR); + m_jit.move(TrustedImmPtr(globalObject->arrayStructure()), structureGPR); MacroAssembler::Jump done = m_jit.jump(); bigLength.link(&m_jit); - m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)), structureGPR); + m_jit.move(TrustedImmPtr(globalObject->arrayStructureWithArrayStorage()), structureGPR); done.link(&m_jit); callOperation(operationNewArrayWithSize, resultGPR, structureGPR, sizeGPR); cellResult(resultGPR, m_compileIndex); @@ -3767,8 +3520,7 @@ void SpeculativeJIT::compile(Node& node) case NewArrayBuffer: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - IndexingType indexingType = node.indexingType(); - if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) { + if (!globalObject->isHavingABadTime()) { globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); unsigned numElements = node.numConstants(); @@ -3779,23 +3531,13 @@ void SpeculativeJIT::compile(Node& node) GPRReg resultGPR = result.gpr(); GPRReg storageGPR = storage.gpr(); - emitAllocateJSArray(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), resultGPR, storageGPR, numElements); + emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements); - ASSERT(indexingType & IsArray); JSValue* data = m_jit.codeBlock()->constantBuffer(node.startConstant()); - if (indexingType == ArrayWithDouble) { - for (unsigned index = 0; index < node.numConstants(); ++index) { - double value = data[index].asNumber(); - m_jit.store64( - Imm64(bitwise_cast(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)); - } + 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); @@ -3805,7 +3547,7 @@ void SpeculativeJIT::compile(Node& node) flushRegisters(); GPRResult result(this); - callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), node.startConstant(), node.numConstants()); + callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructure(), node.startConstant(), node.numConstants()); cellResult(result.gpr(), m_compileIndex); break; diff --git a/Source/JavaScriptCore/heap/ConservativeRoots.cpp b/Source/JavaScriptCore/heap/ConservativeRoots.cpp index 752ce2775..7fe22dfff 100644 --- a/Source/JavaScriptCore/heap/ConservativeRoots.cpp +++ b/Source/JavaScriptCore/heap/ConservativeRoots.cpp @@ -26,9 +26,9 @@ #include "config.h" #include "ConservativeRoots.h" -#include "CodeBlock.h" #include "CopiedSpace.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.h" +#include "CodeBlock.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 83fdb08da..af36f55df 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 "JSValueInlines.h" +#include "JSValueInlineMethods.h" #include "Options.h" #include diff --git a/Source/JavaScriptCore/heap/CopiedSpace.cpp b/Source/JavaScriptCore/heap/CopiedSpace.cpp index e4141c1d7..c228f9460 100644 --- a/Source/JavaScriptCore/heap/CopiedSpace.cpp +++ b/Source/JavaScriptCore/heap/CopiedSpace.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "CopiedSpace.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.h" #include "GCActivityCallback.h" #include "Options.h" diff --git a/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h b/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h new file mode 100644 index 000000000..c244015e7 --- /dev/null +++ b/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CopiedSpaceInlineMethods_h +#define CopiedSpaceInlineMethods_h + +#include "CopiedBlock.h" +#include "CopiedSpace.h" +#include "Heap.h" +#include "HeapBlock.h" +#include "JSGlobalData.h" +#include + +namespace JSC { + +inline bool CopiedSpace::contains(CopiedBlock* block) +{ + return !m_blockFilter.ruleOut(reinterpret_cast(block)) && m_blockSet.contains(block); +} + +inline bool CopiedSpace::contains(void* ptr, CopiedBlock*& result) +{ + CopiedBlock* block = blockFor(ptr); + if (contains(block)) { + result = block; + return true; + } + block = oversizeBlockFor(ptr); + result = block; + return contains(block); +} + +inline void CopiedSpace::pin(CopiedBlock* block) +{ + block->m_isPinned = true; +} + +inline void CopiedSpace::pinIfNecessary(void* opaquePointer) +{ + // Pointers into the copied space come in the following varieties: + // 1) Pointers to the start of a span of memory. This is the most + // natural though not necessarily the most common. + // 2) Pointers to one value-sized (8 byte) word past the end of + // a span of memory. This currently occurs with semi-butterflies + // and should be fixed soon, once the other half of the + // butterfly lands. + // 3) Pointers to the innards arising from loop induction variable + // optimizations (either manual ones or automatic, by the + // compiler). + // 4) Pointers to the end of a span of memory in arising from + // induction variable optimizations combined with the + // GC-to-compiler contract laid out in the C spec: a pointer to + // the end of a span of memory must be considered to be a + // pointer to that memory. + + EncodedJSValue* pointer = reinterpret_cast(opaquePointer); + CopiedBlock* block; + + // Handle (1) and (3). + if (contains(pointer, block)) + pin(block); + + // Handle (4). We don't have to explicitly check and pin the block under this + // pointer because it cannot possibly point to something that cases (1) and + // (3) above or case (2) below wouldn't already catch. + pointer--; + + // Handle (2) + pointer--; + if (contains(pointer, block)) + pin(block); +} + +inline void CopiedSpace::recycleEvacuatedBlock(CopiedBlock* block) +{ + ASSERT(block); + ASSERT(block->canBeRecycled()); + ASSERT(!block->m_isPinned); + { + SpinLockHolder locker(&m_toSpaceLock); + m_blockSet.remove(block); + m_fromSpace->remove(block); + } + m_heap->blockAllocator().deallocate(CopiedBlock::destroy(block)); +} + +inline void CopiedSpace::recycleBorrowedBlock(CopiedBlock* block) +{ + m_heap->blockAllocator().deallocate(CopiedBlock::destroy(block)); + + { + MutexLocker locker(m_loanedBlocksLock); + ASSERT(m_numberOfLoanedBlocks > 0); + ASSERT(m_inCopyingPhase); + m_numberOfLoanedBlocks--; + if (!m_numberOfLoanedBlocks) + m_loanedBlocksCondition.signal(); + } +} + +inline CopiedBlock* CopiedSpace::allocateBlockForCopyingPhase() +{ + ASSERT(m_inCopyingPhase); + CopiedBlock* block = CopiedBlock::createNoZeroFill(m_heap->blockAllocator().allocate()); + + { + MutexLocker locker(m_loanedBlocksLock); + m_numberOfLoanedBlocks++; + } + + ASSERT(!block->dataSize()); + return block; +} + +inline void CopiedSpace::allocateBlock() +{ + if (m_heap->shouldCollect()) + m_heap->collect(Heap::DoNotSweep); + + m_allocator.resetCurrentBlock(); + + CopiedBlock* block = CopiedBlock::create(m_heap->blockAllocator().allocate()); + + m_toSpace->push(block); + m_blockFilter.add(reinterpret_cast(block)); + m_blockSet.add(block); + m_allocator.setCurrentBlock(block); +} + +inline CheckedBoolean CopiedSpace::tryAllocate(size_t bytes, void** outPtr) +{ + ASSERT(!m_heap->globalData()->isInitializingObject()); + + if (isOversize(bytes) || !m_allocator.tryAllocate(bytes, outPtr)) + return tryAllocateSlowCase(bytes, outPtr); + + ASSERT(*outPtr); + return true; +} + +inline bool CopiedSpace::isOversize(size_t bytes) +{ + return bytes > s_maxAllocationSize; +} + +inline bool CopiedSpace::isPinned(void* ptr) +{ + return blockFor(ptr)->m_isPinned; +} + +inline CopiedBlock* CopiedSpace::oversizeBlockFor(void* ptr) +{ + return reinterpret_cast(reinterpret_cast(ptr) & WTF::pageMask()); +} + +inline CopiedBlock* CopiedSpace::blockFor(void* ptr) +{ + return reinterpret_cast(reinterpret_cast(ptr) & s_blockMask); +} + +} // namespace JSC + +#endif diff --git a/Source/JavaScriptCore/heap/CopiedSpaceInlines.h b/Source/JavaScriptCore/heap/CopiedSpaceInlines.h deleted file mode 100644 index 9d222f549..000000000 --- a/Source/JavaScriptCore/heap/CopiedSpaceInlines.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 CopiedSpaceInlines_h -#define CopiedSpaceInlines_h - -#include "CopiedBlock.h" -#include "CopiedSpace.h" -#include "Heap.h" -#include "HeapBlock.h" -#include "JSGlobalData.h" -#include - -namespace JSC { - -inline bool CopiedSpace::contains(CopiedBlock* block) -{ - return !m_blockFilter.ruleOut(reinterpret_cast(block)) && m_blockSet.contains(block); -} - -inline bool CopiedSpace::contains(void* ptr, CopiedBlock*& result) -{ - CopiedBlock* block = blockFor(ptr); - if (contains(block)) { - result = block; - return true; - } - block = oversizeBlockFor(ptr); - result = block; - return contains(block); -} - -inline void CopiedSpace::pin(CopiedBlock* block) -{ - block->m_isPinned = true; -} - -inline void CopiedSpace::pinIfNecessary(void* opaquePointer) -{ - // Pointers into the copied space come in the following varieties: - // 1) Pointers to the start of a span of memory. This is the most - // natural though not necessarily the most common. - // 2) Pointers to one value-sized (8 byte) word past the end of - // a span of memory. This currently occurs with semi-butterflies - // and should be fixed soon, once the other half of the - // butterfly lands. - // 3) Pointers to the innards arising from loop induction variable - // optimizations (either manual ones or automatic, by the - // compiler). - // 4) Pointers to the end of a span of memory in arising from - // induction variable optimizations combined with the - // GC-to-compiler contract laid out in the C spec: a pointer to - // the end of a span of memory must be considered to be a - // pointer to that memory. - - EncodedJSValue* pointer = reinterpret_cast(opaquePointer); - CopiedBlock* block; - - // Handle (1) and (3). - if (contains(pointer, block)) - pin(block); - - // Handle (4). We don't have to explicitly check and pin the block under this - // pointer because it cannot possibly point to something that cases (1) and - // (3) above or case (2) below wouldn't already catch. - pointer--; - - // Handle (2) - pointer--; - if (contains(pointer, block)) - pin(block); -} - -inline void CopiedSpace::recycleEvacuatedBlock(CopiedBlock* block) -{ - ASSERT(block); - ASSERT(block->canBeRecycled()); - ASSERT(!block->m_isPinned); - { - SpinLockHolder locker(&m_toSpaceLock); - m_blockSet.remove(block); - m_fromSpace->remove(block); - } - m_heap->blockAllocator().deallocate(CopiedBlock::destroy(block)); -} - -inline void CopiedSpace::recycleBorrowedBlock(CopiedBlock* block) -{ - m_heap->blockAllocator().deallocate(CopiedBlock::destroy(block)); - - { - MutexLocker locker(m_loanedBlocksLock); - ASSERT(m_numberOfLoanedBlocks > 0); - ASSERT(m_inCopyingPhase); - m_numberOfLoanedBlocks--; - if (!m_numberOfLoanedBlocks) - m_loanedBlocksCondition.signal(); - } -} - -inline CopiedBlock* CopiedSpace::allocateBlockForCopyingPhase() -{ - ASSERT(m_inCopyingPhase); - CopiedBlock* block = CopiedBlock::createNoZeroFill(m_heap->blockAllocator().allocate()); - - { - MutexLocker locker(m_loanedBlocksLock); - m_numberOfLoanedBlocks++; - } - - ASSERT(!block->dataSize()); - return block; -} - -inline void CopiedSpace::allocateBlock() -{ - if (m_heap->shouldCollect()) - m_heap->collect(Heap::DoNotSweep); - - m_allocator.resetCurrentBlock(); - - CopiedBlock* block = CopiedBlock::create(m_heap->blockAllocator().allocate()); - - m_toSpace->push(block); - m_blockFilter.add(reinterpret_cast(block)); - m_blockSet.add(block); - m_allocator.setCurrentBlock(block); -} - -inline CheckedBoolean CopiedSpace::tryAllocate(size_t bytes, void** outPtr) -{ - ASSERT(!m_heap->globalData()->isInitializingObject()); - - if (isOversize(bytes) || !m_allocator.tryAllocate(bytes, outPtr)) - return tryAllocateSlowCase(bytes, outPtr); - - ASSERT(*outPtr); - return true; -} - -inline bool CopiedSpace::isOversize(size_t bytes) -{ - return bytes > s_maxAllocationSize; -} - -inline bool CopiedSpace::isPinned(void* ptr) -{ - return blockFor(ptr)->m_isPinned; -} - -inline CopiedBlock* CopiedSpace::oversizeBlockFor(void* ptr) -{ - return reinterpret_cast(reinterpret_cast(ptr) & WTF::pageMask()); -} - -inline CopiedBlock* CopiedSpace::blockFor(void* ptr) -{ - return reinterpret_cast(reinterpret_cast(ptr) & s_blockMask); -} - -} // namespace JSC - -#endif // CopiedSpaceInlines_h - diff --git a/Source/JavaScriptCore/heap/CopyVisitor.cpp b/Source/JavaScriptCore/heap/CopyVisitor.cpp index 22ab57882..ae826f0d2 100644 --- a/Source/JavaScriptCore/heap/CopyVisitor.cpp +++ b/Source/JavaScriptCore/heap/CopyVisitor.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "CopyVisitor.h" -#include "CopyVisitorInlines.h" +#include "CopyVisitorInlineMethods.h" #include "GCThreadSharedData.h" #include "JSCell.h" #include "JSObject.h" diff --git a/Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h b/Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h new file mode 100644 index 000000000..eb7bd2e82 --- /dev/null +++ b/Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h @@ -0,0 +1,119 @@ +/* + * 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. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CopyVisitorInlineMethods_h +#define CopyVisitorInlineMethods_h + +#include "ClassInfo.h" +#include "CopyVisitor.h" +#include "GCThreadSharedData.h" +#include "JSCell.h" +#include "JSDestructibleObject.h" + +namespace JSC { + +class GCCopyPhaseFunctor : public MarkedBlock::VoidFunctor { +public: + GCCopyPhaseFunctor(CopyVisitor& visitor) + : m_visitor(visitor) + { + } + + void operator()(JSCell* cell) + { + Structure* structure = cell->structure(); + if (!structure->outOfLineCapacity() && !hasIndexedProperties(structure->indexingType())) + return; + ASSERT(structure->classInfo()->methodTable.copyBackingStore == JSObject::copyBackingStore); + JSObject::copyBackingStore(cell, m_visitor); + } + +private: + CopyVisitor& m_visitor; +}; + +inline bool CopyVisitor::checkIfShouldCopy(void* oldPtr, size_t bytes) +{ + if (CopiedSpace::isOversize(bytes)) + return false; + + if (CopiedSpace::blockFor(oldPtr)->isPinned()) + return false; + + return true; +} + +inline void* CopyVisitor::allocateNewSpace(size_t bytes) +{ + void* result = 0; // Compilers don't realize that this will be assigned. + if (LIKELY(m_copiedAllocator.tryAllocate(bytes, &result))) + return result; + + result = allocateNewSpaceSlow(bytes); + ASSERT(result); + return result; +} + +inline void* CopyVisitor::allocateNewSpaceSlow(size_t bytes) +{ + CopiedBlock* newBlock = 0; + m_shared.m_copiedSpace->doneFillingBlock(m_copiedAllocator.resetCurrentBlock(), &newBlock); + m_copiedAllocator.setCurrentBlock(newBlock); + + void* result = 0; + CheckedBoolean didSucceed = m_copiedAllocator.tryAllocate(bytes, &result); + ASSERT(didSucceed); + return result; +} + +inline void CopyVisitor::startCopying() +{ + ASSERT(!m_copiedAllocator.isValid()); + CopiedBlock* block = 0; + m_shared.m_copiedSpace->doneFillingBlock(m_copiedAllocator.resetCurrentBlock(), &block); + m_copiedAllocator.setCurrentBlock(block); +} + +inline void CopyVisitor::doneCopying() +{ + if (!m_copiedAllocator.isValid()) + return; + + m_shared.m_copiedSpace->doneFillingBlock(m_copiedAllocator.resetCurrentBlock(), 0); +} + +inline void CopyVisitor::didCopy(void* ptr, size_t bytes) +{ + ASSERT(!CopiedSpace::isOversize(bytes)); + CopiedBlock* block = CopiedSpace::blockFor(ptr); + ASSERT(!block->isPinned()); + + if (block->didEvacuateBytes(bytes)) + m_shared.m_copiedSpace->recycleEvacuatedBlock(block); +} + +} // namespace JSC + +#endif diff --git a/Source/JavaScriptCore/heap/CopyVisitorInlines.h b/Source/JavaScriptCore/heap/CopyVisitorInlines.h deleted file mode 100644 index bd7879429..000000000 --- a/Source/JavaScriptCore/heap/CopyVisitorInlines.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CopyVisitorInlines_h -#define CopyVisitorInlines_h - -#include "ClassInfo.h" -#include "CopyVisitor.h" -#include "GCThreadSharedData.h" -#include "JSCell.h" -#include "JSDestructibleObject.h" - -namespace JSC { - -class GCCopyPhaseFunctor : public MarkedBlock::VoidFunctor { -public: - GCCopyPhaseFunctor(CopyVisitor& visitor) - : m_visitor(visitor) - { - } - - void operator()(JSCell* cell) - { - Structure* structure = cell->structure(); - if (!structure->outOfLineCapacity() && !hasIndexedProperties(structure->indexingType())) - return; - ASSERT(structure->classInfo()->methodTable.copyBackingStore == JSObject::copyBackingStore); - JSObject::copyBackingStore(cell, m_visitor); - } - -private: - CopyVisitor& m_visitor; -}; - -inline bool CopyVisitor::checkIfShouldCopy(void* oldPtr, size_t bytes) -{ - if (CopiedSpace::isOversize(bytes)) - return false; - - if (CopiedSpace::blockFor(oldPtr)->isPinned()) - return false; - - return true; -} - -inline void* CopyVisitor::allocateNewSpace(size_t bytes) -{ - void* result = 0; // Compilers don't realize that this will be assigned. - if (LIKELY(m_copiedAllocator.tryAllocate(bytes, &result))) - return result; - - result = allocateNewSpaceSlow(bytes); - ASSERT(result); - return result; -} - -inline void* CopyVisitor::allocateNewSpaceSlow(size_t bytes) -{ - CopiedBlock* newBlock = 0; - m_shared.m_copiedSpace->doneFillingBlock(m_copiedAllocator.resetCurrentBlock(), &newBlock); - m_copiedAllocator.setCurrentBlock(newBlock); - - void* result = 0; - CheckedBoolean didSucceed = m_copiedAllocator.tryAllocate(bytes, &result); - ASSERT(didSucceed); - return result; -} - -inline void CopyVisitor::startCopying() -{ - ASSERT(!m_copiedAllocator.isValid()); - CopiedBlock* block = 0; - m_shared.m_copiedSpace->doneFillingBlock(m_copiedAllocator.resetCurrentBlock(), &block); - m_copiedAllocator.setCurrentBlock(block); -} - -inline void CopyVisitor::doneCopying() -{ - if (!m_copiedAllocator.isValid()) - return; - - m_shared.m_copiedSpace->doneFillingBlock(m_copiedAllocator.resetCurrentBlock(), 0); -} - -inline void CopyVisitor::didCopy(void* ptr, size_t bytes) -{ - ASSERT(!CopiedSpace::isOversize(bytes)); - CopiedBlock* block = CopiedSpace::blockFor(ptr); - ASSERT(!block->isPinned()); - - if (block->didEvacuateBytes(bytes)) - m_shared.m_copiedSpace->recycleEvacuatedBlock(block); -} - -} // namespace JSC - -#endif // CopyVisitorInlines_h - diff --git a/Source/JavaScriptCore/heap/GCThread.cpp b/Source/JavaScriptCore/heap/GCThread.cpp index 7caa7d588..ce3bbedc9 100644 --- a/Source/JavaScriptCore/heap/GCThread.cpp +++ b/Source/JavaScriptCore/heap/GCThread.cpp @@ -27,7 +27,7 @@ #include "GCThread.h" #include "CopyVisitor.h" -#include "CopyVisitorInlines.h" +#include "CopyVisitorInlineMethods.h" #include "GCThreadSharedData.h" #include "SlotVisitor.h" #include diff --git a/Source/JavaScriptCore/heap/GCThreadSharedData.cpp b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp index cf12d4bcd..446b41c2f 100644 --- a/Source/JavaScriptCore/heap/GCThreadSharedData.cpp +++ b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp @@ -27,12 +27,12 @@ #include "GCThreadSharedData.h" #include "CopyVisitor.h" -#include "CopyVisitorInlines.h" +#include "CopyVisitorInlineMethods.h" #include "GCThread.h" #include "JSGlobalData.h" #include "MarkStack.h" #include "SlotVisitor.h" -#include "SlotVisitorInlines.h" +#include "SlotVisitorInlineMethods.h" namespace JSC { diff --git a/Source/JavaScriptCore/heap/HandleStack.cpp b/Source/JavaScriptCore/heap/HandleStack.cpp index a5653c748..42eb326a5 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 0fb65e205..c455fc2b1 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 "CopiedSpaceInlines.h" -#include "CopyVisitorInlines.h" +#include "CopiedSpaceInlineMethods.h" +#include "CopyVisitorInlineMethods.h" #include "GCActivityCallback.h" #include "HeapRootVisitor.h" #include "HeapStatistics.h" diff --git a/Source/JavaScriptCore/heap/HeapRootVisitor.h b/Source/JavaScriptCore/heap/HeapRootVisitor.h index 5b11a5ead..9849d7c39 100644 --- a/Source/JavaScriptCore/heap/HeapRootVisitor.h +++ b/Source/JavaScriptCore/heap/HeapRootVisitor.h @@ -27,7 +27,7 @@ #define HeapRootVisitor_h #include "SlotVisitor.h" -#include "SlotVisitorInlines.h" +#include "SlotVisitorInlineMethods.h" namespace JSC { diff --git a/Source/JavaScriptCore/heap/HeapStatistics.cpp b/Source/JavaScriptCore/heap/HeapStatistics.cpp index 387621558..8340bfa37 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; -Vector* HeapStatistics::s_pauseTimeStarts = 0; -Vector* HeapStatistics::s_pauseTimeEnds = 0; +Deque* HeapStatistics::s_pauseTimeStarts = 0; +Deque* HeapStatistics::s_pauseTimeEnds = 0; #if OS(UNIX) @@ -50,8 +50,8 @@ void HeapStatistics::initialize() { ASSERT(Options::recordGCPauseTimes()); s_startTime = WTF::monotonicallyIncreasingTime(); - s_pauseTimeStarts = new Vector(); - s_pauseTimeEnds = new Vector(); + s_pauseTimeStarts = new Deque(); + s_pauseTimeEnds = new Deque(); } void HeapStatistics::recordGCPauseTime(double start, double end) @@ -82,8 +82,8 @@ void HeapStatistics::logStatistics() if (Options::recordGCPauseTimes()) { dataLog(", \"pause_times\": ["); - Vector::iterator startIt = s_pauseTimeStarts->begin(); - Vector::iterator endIt = s_pauseTimeEnds->begin(); + Deque::iterator startIt = s_pauseTimeStarts->begin(); + Deque::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 ce7a40a79..0800f0c16 100644 --- a/Source/JavaScriptCore/heap/HeapStatistics.h +++ b/Source/JavaScriptCore/heap/HeapStatistics.h @@ -49,8 +49,8 @@ public: private: static void logStatistics(); - static Vector* s_pauseTimeStarts; - static Vector* s_pauseTimeEnds; + static Deque* s_pauseTimeStarts; + static Deque* 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 aa8785e9c..582439fd2 100644 --- a/Source/JavaScriptCore/heap/MarkStack.cpp +++ b/Source/JavaScriptCore/heap/MarkStack.cpp @@ -25,18 +25,18 @@ #include "config.h" #include "MarkStack.h" -#include "MarkStackInlines.h" +#include "MarkStackInlineMethods.h" -#include "ConservativeRoots.h" #include "CopiedSpace.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.h" +#include "ConservativeRoots.h" #include "Heap.h" #include "Options.h" #include "JSArray.h" #include "JSCell.h" #include "JSObject.h" -#include "SlotVisitorInlines.h" +#include "SlotVisitorInlineMethods.h" #include "Structure.h" #include "WriteBarrier.h" #include diff --git a/Source/JavaScriptCore/heap/MarkStackInlineMethods.h b/Source/JavaScriptCore/heap/MarkStackInlineMethods.h new file mode 100644 index 000000000..d3276d7fa --- /dev/null +++ b/Source/JavaScriptCore/heap/MarkStackInlineMethods.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2009, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MarkStackInlineMethods_h +#define MarkStackInlineMethods_h + +#include "GCThreadSharedData.h" +#include "MarkStack.h" + +namespace JSC { + +inline size_t MarkStackArray::postIncTop() +{ + size_t result = m_top++; + 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); + m_top = m_segmentCapacity; +} + +inline void MarkStackArray::setTopForEmptySegment() +{ + ASSERT(!m_topSegment->m_top); + m_top = 0; +} + +inline size_t MarkStackArray::top() +{ + ASSERT(m_top == m_topSegment->m_top); + return m_top; +} + +#if ASSERT_DISABLED +inline void MarkStackArray::validatePrevious() { } +#else +inline void MarkStackArray::validatePrevious() +{ + unsigned count = 0; + for (MarkStackSegment* current = m_topSegment->m_previous; current; current = current->m_previous) + count++; + ASSERT(count == m_numberOfPreviousSegments); +} +#endif + +inline void MarkStackArray::append(const JSCell* cell) +{ + if (m_top == m_segmentCapacity) + expand(); + m_topSegment->data()[postIncTop()] = cell; +} + +inline bool MarkStackArray::canRemoveLast() +{ + return !!m_top; +} + +inline const JSCell* MarkStackArray::removeLast() +{ + return m_topSegment->data()[preDecTop()]; +} + +inline bool MarkStackArray::isEmpty() +{ + if (m_top) + return false; + if (m_topSegment->m_previous) { + ASSERT(m_topSegment->m_previous->m_top == m_segmentCapacity); + return false; + } + return true; +} + +inline size_t MarkStackArray::size() +{ + return m_top + m_segmentCapacity * m_numberOfPreviousSegments; +} + +} // namespace JSC + +#endif diff --git a/Source/JavaScriptCore/heap/MarkStackInlines.h b/Source/JavaScriptCore/heap/MarkStackInlines.h deleted file mode 100644 index 841ac06b8..000000000 --- a/Source/JavaScriptCore/heap/MarkStackInlines.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2009, 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef MarkStackInlines_h -#define MarkStackInlines_h - -#include "GCThreadSharedData.h" -#include "MarkStack.h" - -namespace JSC { - -inline size_t MarkStackArray::postIncTop() -{ - size_t result = m_top++; - 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); - m_top = m_segmentCapacity; -} - -inline void MarkStackArray::setTopForEmptySegment() -{ - ASSERT(!m_topSegment->m_top); - m_top = 0; -} - -inline size_t MarkStackArray::top() -{ - ASSERT(m_top == m_topSegment->m_top); - return m_top; -} - -#if ASSERT_DISABLED -inline void MarkStackArray::validatePrevious() { } -#else -inline void MarkStackArray::validatePrevious() -{ - unsigned count = 0; - for (MarkStackSegment* current = m_topSegment->m_previous; current; current = current->m_previous) - count++; - ASSERT(count == m_numberOfPreviousSegments); -} -#endif - -inline void MarkStackArray::append(const JSCell* cell) -{ - if (m_top == m_segmentCapacity) - expand(); - m_topSegment->data()[postIncTop()] = cell; -} - -inline bool MarkStackArray::canRemoveLast() -{ - return !!m_top; -} - -inline const JSCell* MarkStackArray::removeLast() -{ - return m_topSegment->data()[preDecTop()]; -} - -inline bool MarkStackArray::isEmpty() -{ - if (m_top) - return false; - if (m_topSegment->m_previous) { - ASSERT(m_topSegment->m_previous->m_top == m_segmentCapacity); - return false; - } - return true; -} - -inline size_t MarkStackArray::size() -{ - return m_top + m_segmentCapacity * m_numberOfPreviousSegments; -} - -} // namespace JSC - -#endif // MarkStackInlines_h - diff --git a/Source/JavaScriptCore/heap/SlotVisitor.cpp b/Source/JavaScriptCore/heap/SlotVisitor.cpp index 8b4d7397e..3919705d0 100644 --- a/Source/JavaScriptCore/heap/SlotVisitor.cpp +++ b/Source/JavaScriptCore/heap/SlotVisitor.cpp @@ -3,7 +3,7 @@ #include "ConservativeRoots.h" #include "CopiedSpace.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.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 34b1bc80b..dcd4b75ef 100644 --- a/Source/JavaScriptCore/heap/SlotVisitor.h +++ b/Source/JavaScriptCore/heap/SlotVisitor.h @@ -27,7 +27,7 @@ #define SlotVisitor_h #include "HandleTypes.h" -#include "MarkStackInlines.h" +#include "MarkStackInlineMethods.h" #include diff --git a/Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h b/Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h new file mode 100644 index 000000000..e5908bf36 --- /dev/null +++ b/Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h @@ -0,0 +1,174 @@ +/* + * 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. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SlotVisitorInlineMethods_h +#define SlotVisitorInlineMethods_h + +#include "CopiedSpaceInlineMethods.h" +#include "Options.h" +#include "SlotVisitor.h" + +namespace JSC { + +ALWAYS_INLINE void SlotVisitor::append(JSValue* slot, size_t count) +{ + for (size_t i = 0; i < count; ++i) { + JSValue& value = slot[i]; + internalAppend(value); + } +} + +template +inline void SlotVisitor::appendUnbarrieredPointer(T** slot) +{ + ASSERT(slot); + JSCell* cell = *slot; + internalAppend(cell); +} + +ALWAYS_INLINE void SlotVisitor::append(JSValue* slot) +{ + ASSERT(slot); + internalAppend(*slot); +} + +ALWAYS_INLINE void SlotVisitor::appendUnbarrieredValue(JSValue* slot) +{ + ASSERT(slot); + internalAppend(*slot); +} + +ALWAYS_INLINE void SlotVisitor::append(JSCell** slot) +{ + ASSERT(slot); + internalAppend(*slot); +} + +ALWAYS_INLINE void SlotVisitor::internalAppend(JSValue value) +{ + if (!value || !value.isCell()) + return; + internalAppend(value.asCell()); +} + +inline void SlotVisitor::addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester) +{ + m_shared.m_weakReferenceHarvesters.addThreadSafe(weakReferenceHarvester); +} + +inline void SlotVisitor::addUnconditionalFinalizer(UnconditionalFinalizer* unconditionalFinalizer) +{ + m_shared.m_unconditionalFinalizers.addThreadSafe(unconditionalFinalizer); +} + +inline void SlotVisitor::addOpaqueRoot(void* root) +{ +#if ENABLE(PARALLEL_GC) + if (Options::numberOfGCMarkers() == 1) { + // Put directly into the shared HashSet. + m_shared.m_opaqueRoots.add(root); + return; + } + // Put into the local set, but merge with the shared one every once in + // a while to make sure that the local sets don't grow too large. + mergeOpaqueRootsIfProfitable(); + m_opaqueRoots.add(root); +#else + m_opaqueRoots.add(root); +#endif +} + +inline bool SlotVisitor::containsOpaqueRoot(void* root) +{ + ASSERT(!m_isInParallelMode); +#if ENABLE(PARALLEL_GC) + ASSERT(m_opaqueRoots.isEmpty()); + return m_shared.m_opaqueRoots.contains(root); +#else + return m_opaqueRoots.contains(root); +#endif +} + +inline int SlotVisitor::opaqueRootCount() +{ + ASSERT(!m_isInParallelMode); +#if ENABLE(PARALLEL_GC) + ASSERT(m_opaqueRoots.isEmpty()); + return m_shared.m_opaqueRoots.size(); +#else + return m_opaqueRoots.size(); +#endif +} + +inline void SlotVisitor::mergeOpaqueRootsIfNecessary() +{ + if (m_opaqueRoots.isEmpty()) + return; + mergeOpaqueRoots(); +} + +inline void SlotVisitor::mergeOpaqueRootsIfProfitable() +{ + if (static_cast(m_opaqueRoots.size()) < Options::opaqueRootMergeThreshold()) + return; + mergeOpaqueRoots(); +} + +inline void SlotVisitor::donate() +{ + ASSERT(m_isInParallelMode); + if (Options::numberOfGCMarkers() == 1) + return; + + donateKnownParallel(); +} + +inline void SlotVisitor::donateAndDrain() +{ + donate(); + drain(); +} + +inline void SlotVisitor::copyLater(void* ptr, size_t bytes) +{ + if (CopiedSpace::isOversize(bytes)) { + m_shared.m_copiedSpace->pin(CopiedSpace::oversizeBlockFor(ptr)); + return; + } + + CopiedBlock* block = CopiedSpace::blockFor(ptr); + if (block->isPinned()) + return; + + block->reportLiveBytes(bytes); + + if (!block->shouldEvacuate()) + m_shared.m_copiedSpace->pin(block); +} + +} // namespace JSC + +#endif // SlotVisitorInlineMethods_h + diff --git a/Source/JavaScriptCore/heap/SlotVisitorInlines.h b/Source/JavaScriptCore/heap/SlotVisitorInlines.h deleted file mode 100644 index b0f30b6ca..000000000 --- a/Source/JavaScriptCore/heap/SlotVisitorInlines.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SlotVisitorInlines_h -#define SlotVisitorInlines_h - -#include "CopiedSpaceInlines.h" -#include "Options.h" -#include "SlotVisitor.h" - -namespace JSC { - -ALWAYS_INLINE void SlotVisitor::append(JSValue* slot, size_t count) -{ - for (size_t i = 0; i < count; ++i) { - JSValue& value = slot[i]; - internalAppend(value); - } -} - -template -inline void SlotVisitor::appendUnbarrieredPointer(T** slot) -{ - ASSERT(slot); - JSCell* cell = *slot; - internalAppend(cell); -} - -ALWAYS_INLINE void SlotVisitor::append(JSValue* slot) -{ - ASSERT(slot); - internalAppend(*slot); -} - -ALWAYS_INLINE void SlotVisitor::appendUnbarrieredValue(JSValue* slot) -{ - ASSERT(slot); - internalAppend(*slot); -} - -ALWAYS_INLINE void SlotVisitor::append(JSCell** slot) -{ - ASSERT(slot); - internalAppend(*slot); -} - -ALWAYS_INLINE void SlotVisitor::internalAppend(JSValue value) -{ - if (!value || !value.isCell()) - return; - internalAppend(value.asCell()); -} - -inline void SlotVisitor::addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester) -{ - m_shared.m_weakReferenceHarvesters.addThreadSafe(weakReferenceHarvester); -} - -inline void SlotVisitor::addUnconditionalFinalizer(UnconditionalFinalizer* unconditionalFinalizer) -{ - m_shared.m_unconditionalFinalizers.addThreadSafe(unconditionalFinalizer); -} - -inline void SlotVisitor::addOpaqueRoot(void* root) -{ -#if ENABLE(PARALLEL_GC) - if (Options::numberOfGCMarkers() == 1) { - // Put directly into the shared HashSet. - m_shared.m_opaqueRoots.add(root); - return; - } - // Put into the local set, but merge with the shared one every once in - // a while to make sure that the local sets don't grow too large. - mergeOpaqueRootsIfProfitable(); - m_opaqueRoots.add(root); -#else - m_opaqueRoots.add(root); -#endif -} - -inline bool SlotVisitor::containsOpaqueRoot(void* root) -{ - ASSERT(!m_isInParallelMode); -#if ENABLE(PARALLEL_GC) - ASSERT(m_opaqueRoots.isEmpty()); - return m_shared.m_opaqueRoots.contains(root); -#else - return m_opaqueRoots.contains(root); -#endif -} - -inline int SlotVisitor::opaqueRootCount() -{ - ASSERT(!m_isInParallelMode); -#if ENABLE(PARALLEL_GC) - ASSERT(m_opaqueRoots.isEmpty()); - return m_shared.m_opaqueRoots.size(); -#else - return m_opaqueRoots.size(); -#endif -} - -inline void SlotVisitor::mergeOpaqueRootsIfNecessary() -{ - if (m_opaqueRoots.isEmpty()) - return; - mergeOpaqueRoots(); -} - -inline void SlotVisitor::mergeOpaqueRootsIfProfitable() -{ - if (static_cast(m_opaqueRoots.size()) < Options::opaqueRootMergeThreshold()) - return; - mergeOpaqueRoots(); -} - -inline void SlotVisitor::donate() -{ - ASSERT(m_isInParallelMode); - if (Options::numberOfGCMarkers() == 1) - return; - - donateKnownParallel(); -} - -inline void SlotVisitor::donateAndDrain() -{ - donate(); - drain(); -} - -inline void SlotVisitor::copyLater(void* ptr, size_t bytes) -{ - if (CopiedSpace::isOversize(bytes)) { - m_shared.m_copiedSpace->pin(CopiedSpace::oversizeBlockFor(ptr)); - return; - } - - CopiedBlock* block = CopiedSpace::blockFor(ptr); - if (block->isPinned()) - return; - - block->reportLiveBytes(bytes); - - if (!block->shouldEvacuate()) - m_shared.m_copiedSpace->pin(block); -} - -} // namespace JSC - -#endif // SlotVisitorInlines_h - diff --git a/Source/JavaScriptCore/jit/HostCallReturnValue.cpp b/Source/JavaScriptCore/jit/HostCallReturnValue.cpp index 967c499b9..c4d2e6ad9 100644 --- a/Source/JavaScriptCore/jit/HostCallReturnValue.cpp +++ b/Source/JavaScriptCore/jit/HostCallReturnValue.cpp @@ -29,7 +29,7 @@ #include "CallFrame.h" #include #include "JSObject.h" -#include "JSValueInlines.h" +#include "JSValueInlineMethods.h" namespace JSC { diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp index ffd18b571..3102c7693 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 #include "DFGNode.h" // for DFG_SUCCESS_STATS #include "Interpreter.h" -#include "JITInlines.h" +#include "JITInlineMethods.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 9b0879fe2..dcf87d352 100644 --- a/Source/JavaScriptCore/jit/JIT.h +++ b/Source/JavaScriptCore/jit/JIT.h @@ -474,9 +474,7 @@ 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 emitInt32GetByVal(Instruction* instruction, PatchableJump& badType) { return emitContiguousGetByVal(instruction, badType, Int32Shape); } - JumpList emitDoubleGetByVal(Instruction*, PatchableJump& badType); - JumpList emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape = ContiguousShape); + JumpList emitContiguousGetByVal(Instruction*, PatchableJump& badType); 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); @@ -485,20 +483,7 @@ 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 emitInt32PutByVal(Instruction* currentInstruction, PatchableJump& badType) - { - return emitGenericContiguousPutByVal(currentInstruction, badType); - } - JumpList emitDoublePutByVal(Instruction* currentInstruction, PatchableJump& badType) - { - return emitGenericContiguousPutByVal(currentInstruction, badType); - } - JumpList emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) - { - return emitGenericContiguousPutByVal(currentInstruction, badType); - } - template - JumpList emitGenericContiguousPutByVal(Instruction*, PatchableJump& badType); + JumpList emitContiguousPutByVal(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 bcb3dd74a..21d59bc33 100644 --- a/Source/JavaScriptCore/jit/JITArithmetic.cpp +++ b/Source/JavaScriptCore/jit/JITArithmetic.cpp @@ -29,7 +29,7 @@ #include "JIT.h" #include "CodeBlock.h" -#include "JITInlines.h" +#include "JITInlineMethods.h" #include "JITStubCall.h" #include "JITStubs.h" #include "JSArray.h" @@ -1090,20 +1090,18 @@ 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); - moveDoubleTo64(fpRegT0, regT0); - Jump doubleZero = branchTest64(Zero, regT0); add32(TrustedImm32(1), AbsoluteAddress(&m_codeBlock->addSpecialFastCaseProfile(m_bytecodeOffset)->m_counter)); + moveDoubleTo64(fpRegT0, regT0); 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 960d06091..62a359eeb 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 "JITInlines.h" +#include "JITInlineMethods.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 006c5b741..074bf7f97 100644 --- a/Source/JavaScriptCore/jit/JITCall.cpp +++ b/Source/JavaScriptCore/jit/JITCall.cpp @@ -31,7 +31,7 @@ #include "Arguments.h" #include "CodeBlock.h" -#include "JITInlines.h" +#include "JITInlineMethods.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 ecd5cf126..ad827cdf9 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 "JITInlines.h" +#include "JITInlineMethods.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 aeb869474..f6cec24bd 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/JITInlineMethods.h new file mode 100644 index 000000000..410bdf710 --- /dev/null +++ b/Source/JavaScriptCore/jit/JITInlineMethods.h @@ -0,0 +1,1001 @@ +/* + * 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 + * 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 JITInlineMethods_h +#define JITInlineMethods_h + + +#if ENABLE(JIT) + +namespace JSC { + +ALWAYS_INLINE bool JIT::isOperandConstantImmediateDouble(unsigned src) +{ + return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isDouble(); +} + +ALWAYS_INLINE JSValue JIT::getConstantOperand(unsigned src) +{ + ASSERT(m_codeBlock->isConstantRegisterIndex(src)); + return m_codeBlock->getConstant(src); +} + +ALWAYS_INLINE void JIT::emitPutCellToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry) +{ +#if USE(JSVALUE32_64) + store32(TrustedImm32(JSValue::CellTag), tagFor(entry, callFrameRegister)); + store32(from, payloadFor(entry, callFrameRegister)); +#else + store64(from, addressFor(entry, callFrameRegister)); +#endif +} + +ALWAYS_INLINE void JIT::emitPutIntToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry) +{ +#if USE(JSVALUE32_64) + store32(TrustedImm32(Int32Tag), intTagFor(entry, callFrameRegister)); + store32(from, intPayloadFor(entry, callFrameRegister)); +#else + store64(from, addressFor(entry, callFrameRegister)); +#endif +} + +ALWAYS_INLINE void JIT::emitPutToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry) +{ +#if USE(JSVALUE32_64) + storePtr(from, payloadFor(entry, callFrameRegister)); +#else + store64(from, addressFor(entry, callFrameRegister)); +#endif +} + +ALWAYS_INLINE void JIT::emitPutImmediateToCallFrameHeader(void* value, JSStack::CallFrameHeaderEntry entry) +{ + storePtr(TrustedImmPtr(value), Address(callFrameRegister, entry * sizeof(Register))); +} + +ALWAYS_INLINE void JIT::emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from) +{ + loadPtr(Address(from, entry * sizeof(Register)), to); +#if USE(JSVALUE64) + killLastResultRegister(); +#endif +} + +ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader32(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from) +{ + load32(Address(from, entry * sizeof(Register)), to); +#if USE(JSVALUE64) + killLastResultRegister(); +#endif +} + +#if USE(JSVALUE64) +ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader64(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from) +{ + load64(Address(from, entry * sizeof(Register)), to); + killLastResultRegister(); +} +#endif + +ALWAYS_INLINE void JIT::emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures) +{ + failures.append(branchPtr(NotEqual, Address(src, JSCell::structureOffset()), TrustedImmPtr(m_globalData->stringStructure.get()))); + failures.append(branch32(NotEqual, MacroAssembler::Address(src, ThunkHelpers::jsStringLengthOffset()), TrustedImm32(1))); + loadPtr(MacroAssembler::Address(src, ThunkHelpers::jsStringValueOffset()), dst); + failures.append(branchTest32(Zero, dst)); + loadPtr(MacroAssembler::Address(dst, ThunkHelpers::stringImplFlagsOffset()), regT1); + loadPtr(MacroAssembler::Address(dst, ThunkHelpers::stringImplDataOffset()), dst); + + JumpList is16Bit; + JumpList cont8Bit; + is16Bit.append(branchTest32(Zero, regT1, TrustedImm32(ThunkHelpers::stringImpl8BitFlag()))); + load8(MacroAssembler::Address(dst, 0), dst); + cont8Bit.append(jump()); + is16Bit.link(this); + load16(MacroAssembler::Address(dst, 0), dst); + cont8Bit.link(this); +} + +ALWAYS_INLINE JIT::Call JIT::emitNakedCall(CodePtr function) +{ + ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. + + Call nakedCall = nearCall(); + m_calls.append(CallRecord(nakedCall, m_bytecodeOffset, function.executableAddress())); + return nakedCall; +} + +ALWAYS_INLINE bool JIT::atJumpTarget() +{ + while (m_jumpTargetsPosition < m_codeBlock->numberOfJumpTargets() && m_codeBlock->jumpTarget(m_jumpTargetsPosition) <= m_bytecodeOffset) { + if (m_codeBlock->jumpTarget(m_jumpTargetsPosition) == m_bytecodeOffset) + return true; + ++m_jumpTargetsPosition; + } + return false; +} + +#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL + +ALWAYS_INLINE void JIT::beginUninterruptedSequence(int insnSpace, int constSpace) +{ +#if CPU(ARM_TRADITIONAL) +#ifndef NDEBUG + // Ensure the label after the sequence can also fit + insnSpace += sizeof(ARMWord); + constSpace += sizeof(uint64_t); +#endif + + ensureSpace(insnSpace, constSpace); + +#elif CPU(SH4) +#ifndef NDEBUG + insnSpace += sizeof(SH4Word); + constSpace += sizeof(uint64_t); +#endif + + m_assembler.ensureSpace(insnSpace + m_assembler.maxInstructionSize + 2, constSpace + 8); +#endif + +#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL +#ifndef NDEBUG + m_uninterruptedInstructionSequenceBegin = label(); + m_uninterruptedConstantSequenceBegin = sizeOfConstantPool(); +#endif +#endif +} + +ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace, int dst) +{ + UNUSED_PARAM(dst); +#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL + /* There are several cases when the uninterrupted sequence is larger than + * maximum required offset for pathing the same sequence. Eg.: if in a + * uninterrupted sequence the last macroassembler's instruction is a stub + * call, it emits store instruction(s) which should not be included in the + * calculation of length of uninterrupted sequence. So, the insnSpace and + * constSpace should be upper limit instead of hard limit. + */ +#if CPU(SH4) + if ((dst > 15) || (dst < -16)) { + insnSpace += 8; + constSpace += 2; + } + + if (((dst >= -16) && (dst < 0)) || ((dst > 7) && (dst <= 15))) + insnSpace += 8; +#endif + ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) <= insnSpace); + ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin <= constSpace); +#endif +} + +#endif + +#if CPU(ARM) + +ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg) +{ + move(linkRegister, reg); +} + +ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg) +{ + move(reg, linkRegister); +} + +ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) +{ + loadPtr(address, linkRegister); +} +#elif CPU(SH4) + +ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg) +{ + m_assembler.stspr(reg); +} + +ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg) +{ + m_assembler.ldspr(reg); +} + +ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) +{ + loadPtrLinkReg(address); +} + +#elif CPU(MIPS) + +ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg) +{ + move(returnAddressRegister, reg); +} + +ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg) +{ + move(reg, returnAddressRegister); +} + +ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) +{ + loadPtr(address, returnAddressRegister); +} + +#else // CPU(X86) || CPU(X86_64) + +ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg) +{ + pop(reg); +} + +ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg) +{ + push(reg); +} + +ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) +{ + push(address); +} + +#endif + +ALWAYS_INLINE void JIT::restoreArgumentReference() +{ + move(stackPointerRegister, firstArgumentRegister); + poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); +} + +ALWAYS_INLINE void JIT::updateTopCallFrame() +{ + ASSERT(static_cast(m_bytecodeOffset) >= 0); + if (m_bytecodeOffset) { +#if USE(JSVALUE32_64) + storePtr(TrustedImmPtr(m_codeBlock->instructions().begin() + m_bytecodeOffset + 1), intTagFor(JSStack::ArgumentCount)); +#else + store32(TrustedImm32(m_bytecodeOffset + 1), intTagFor(JSStack::ArgumentCount)); +#endif + } + storePtr(callFrameRegister, &m_globalData->topCallFrame); +} + +ALWAYS_INLINE void JIT::restoreArgumentReferenceForTrampoline() +{ +#if CPU(X86) + // Within a trampoline the return address will be on the stack at this point. + addPtr(TrustedImm32(sizeof(void*)), stackPointerRegister, firstArgumentRegister); +#elif CPU(ARM) + move(stackPointerRegister, firstArgumentRegister); +#elif CPU(SH4) + move(stackPointerRegister, firstArgumentRegister); +#endif + // In the trampoline on x86-64, the first argument register is not overwritten. +} + +ALWAYS_INLINE JIT::Jump JIT::checkStructure(RegisterID reg, Structure* structure) +{ + return branchPtr(NotEqual, Address(reg, JSCell::structureOffset()), TrustedImmPtr(structure)); +} + +ALWAYS_INLINE void JIT::linkSlowCaseIfNotJSCell(Vector::iterator& iter, int vReg) +{ + if (!m_codeBlock->isKnownNotImmediate(vReg)) + linkSlowCase(iter); +} + +ALWAYS_INLINE void JIT::addSlowCase(Jump jump) +{ + ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. + + m_slowCases.append(SlowCaseEntry(jump, m_bytecodeOffset)); +} + +ALWAYS_INLINE void JIT::addSlowCase(JumpList jumpList) +{ + ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. + + const JumpList::JumpVector& jumpVector = jumpList.jumps(); + size_t size = jumpVector.size(); + for (size_t i = 0; i < size; ++i) + m_slowCases.append(SlowCaseEntry(jumpVector[i], m_bytecodeOffset)); +} + +ALWAYS_INLINE void JIT::addSlowCase() +{ + ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. + + Jump emptyJump; // Doing it this way to make Windows happy. + m_slowCases.append(SlowCaseEntry(emptyJump, m_bytecodeOffset)); +} + +ALWAYS_INLINE void JIT::addJump(Jump jump, int relativeOffset) +{ + ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. + + m_jmpTable.append(JumpTable(jump, m_bytecodeOffset + relativeOffset)); +} + +ALWAYS_INLINE void JIT::emitJumpSlowToHot(Jump jump, int relativeOffset) +{ + ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. + + jump.linkTo(m_labels[m_bytecodeOffset + relativeOffset], this); +} + +ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotObject(RegisterID structureReg) +{ + return branch8(Below, Address(structureReg, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType)); +} + +ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotType(RegisterID baseReg, RegisterID scratchReg, JSType type) +{ + loadPtr(Address(baseReg, JSCell::structureOffset()), scratchReg); + return branch8(NotEqual, Address(scratchReg, Structure::typeInfoTypeOffset()), TrustedImm32(type)); +} + +#if ENABLE(SAMPLING_FLAGS) +ALWAYS_INLINE void JIT::setSamplingFlag(int32_t flag) +{ + ASSERT(flag >= 1); + ASSERT(flag <= 32); + or32(TrustedImm32(1u << (flag - 1)), AbsoluteAddress(SamplingFlags::addressOfFlags())); +} + +ALWAYS_INLINE void JIT::clearSamplingFlag(int32_t flag) +{ + ASSERT(flag >= 1); + ASSERT(flag <= 32); + and32(TrustedImm32(~(1u << (flag - 1))), AbsoluteAddress(SamplingFlags::addressOfFlags())); +} +#endif + +#if ENABLE(SAMPLING_COUNTERS) +ALWAYS_INLINE void JIT::emitCount(AbstractSamplingCounter& counter, int32_t count) +{ + add64(TrustedImm32(count), AbsoluteAddress(counter.addressOfCounter())); +} +#endif + +#if ENABLE(OPCODE_SAMPLING) +#if CPU(X86_64) +ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction) +{ + move(TrustedImmPtr(m_interpreter->sampler()->sampleSlot()), X86Registers::ecx); + storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), X86Registers::ecx); +} +#else +ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction) +{ + storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), m_interpreter->sampler()->sampleSlot()); +} +#endif +#endif + +#if ENABLE(CODEBLOCK_SAMPLING) +#if CPU(X86_64) +ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock) +{ + move(TrustedImmPtr(m_interpreter->sampler()->codeBlockSlot()), X86Registers::ecx); + storePtr(TrustedImmPtr(codeBlock), X86Registers::ecx); +} +#else +ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock) +{ + storePtr(TrustedImmPtr(codeBlock), m_interpreter->sampler()->codeBlockSlot()); +} +#endif +#endif + +ALWAYS_INLINE bool JIT::isOperandConstantImmediateChar(unsigned src) +{ + return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isString() && asString(getConstantOperand(src).asCell())->length() == 1; +} + +template inline void JIT::emitAllocateBasicJSObject(StructureType structure, RegisterID result, RegisterID storagePtr) +{ + size_t size = ClassType::allocationSize(INLINE_STORAGE_CAPACITY); + MarkedAllocator* allocator = 0; + if (destructorType == MarkedBlock::Normal) + allocator = &m_globalData->heap.allocatorForObjectWithNormalDestructor(size); + else if (destructorType == MarkedBlock::ImmortalStructure) + allocator = &m_globalData->heap.allocatorForObjectWithImmortalStructureDestructor(size); + else + allocator = &m_globalData->heap.allocatorForObjectWithoutDestructor(size); + loadPtr(&allocator->m_freeList.head, result); + addSlowCase(branchTestPtr(Zero, result)); + + // remove the object from the free list + loadPtr(Address(result), storagePtr); + storePtr(storagePtr, &allocator->m_freeList.head); + + // initialize the object's structure + storePtr(structure, Address(result, JSCell::structureOffset())); + + // initialize the object's property storage pointer + storePtr(TrustedImmPtr(0), Address(result, JSObject::butterflyOffset())); +} + +template inline void JIT::emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch) +{ + emitAllocateBasicJSObject(structure, result, scratch); +} + +#if ENABLE(VALUE_PROFILER) +inline void JIT::emitValueProfilingSite(ValueProfile* valueProfile) +{ + ASSERT(shouldEmitProfiling()); + ASSERT(valueProfile); + + const RegisterID value = regT0; +#if USE(JSVALUE32_64) + const RegisterID valueTag = regT1; +#endif + const RegisterID scratch = regT3; + + if (ValueProfile::numberOfBuckets == 1) { + // We're in a simple configuration: only one bucket, so we can just do a direct + // store. +#if USE(JSVALUE64) + store64(value, valueProfile->m_buckets); +#else + EncodedValueDescriptor* descriptor = bitwise_cast(valueProfile->m_buckets); + store32(value, &descriptor->asBits.payload); + store32(valueTag, &descriptor->asBits.tag); +#endif + return; + } + + if (m_randomGenerator.getUint32() & 1) + add32(TrustedImm32(1), bucketCounterRegister); + else + add32(TrustedImm32(3), bucketCounterRegister); + and32(TrustedImm32(ValueProfile::bucketIndexMask), bucketCounterRegister); + move(TrustedImmPtr(valueProfile->m_buckets), scratch); +#if USE(JSVALUE64) + store64(value, BaseIndex(scratch, bucketCounterRegister, TimesEight)); +#elif USE(JSVALUE32_64) + store32(value, BaseIndex(scratch, bucketCounterRegister, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + store32(valueTag, BaseIndex(scratch, bucketCounterRegister, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); +#endif +} + +inline void JIT::emitValueProfilingSite(unsigned bytecodeOffset) +{ + if (!shouldEmitProfiling()) + return; + emitValueProfilingSite(m_codeBlock->valueProfileForBytecodeOffset(bytecodeOffset)); +} + +inline void JIT::emitValueProfilingSite() +{ + emitValueProfilingSite(m_bytecodeOffset); +} +#endif // ENABLE(VALUE_PROFILER) + +inline void JIT::emitArrayProfilingSite(RegisterID structureAndIndexingType, RegisterID scratch, ArrayProfile* arrayProfile) +{ + UNUSED_PARAM(scratch); // We had found this scratch register useful here before, so I will keep it for now. + + RegisterID structure = structureAndIndexingType; + RegisterID indexingType = structureAndIndexingType; + + if (canBeOptimized()) + storePtr(structure, arrayProfile->addressOfLastSeenStructure()); + + load8(Address(structure, Structure::indexingTypeOffset()), indexingType); +} + +inline void JIT::emitArrayProfilingSiteForBytecodeIndex(RegisterID structureAndIndexingType, RegisterID scratch, unsigned bytecodeIndex) +{ +#if ENABLE(VALUE_PROFILER) + emitArrayProfilingSite(structureAndIndexingType, scratch, m_codeBlock->getOrAddArrayProfile(bytecodeIndex)); +#else + UNUSED_PARAM(bytecodeIndex); + emitArrayProfilingSite(structureAndIndexingType, scratch, 0); +#endif +} + +inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfile) +{ +#if ENABLE(VALUE_PROFILER) + store8(TrustedImm32(1), arrayProfile->addressOfMayStoreToHole()); +#else + UNUSED_PARAM(arrayProfile); +#endif +} + +static inline bool arrayProfileSaw(ArrayProfile* profile, IndexingType capability) +{ +#if ENABLE(VALUE_PROFILER) + return !!(profile->observedArrayModes() & (asArrayModes(NonArray | capability) | asArrayModes(ArrayClass | capability))); +#else + UNUSED_PARAM(profile); + UNUSED_PARAM(capability); + return false; +#endif +} + +inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile) +{ + if (arrayProfileSaw(profile, ArrayStorageShape)) + return JITArrayStorage; + return JITContiguous; +} + +#if USE(JSVALUE32_64) + +inline void JIT::emitLoadTag(int index, RegisterID tag) +{ + RegisterID mappedTag; + if (getMappedTag(index, mappedTag)) { + move(mappedTag, tag); + unmap(tag); + return; + } + + if (m_codeBlock->isConstantRegisterIndex(index)) { + move(Imm32(getConstantOperand(index).tag()), tag); + unmap(tag); + return; + } + + load32(tagFor(index), tag); + unmap(tag); +} + +inline void JIT::emitLoadPayload(int index, RegisterID payload) +{ + RegisterID mappedPayload; + if (getMappedPayload(index, mappedPayload)) { + move(mappedPayload, payload); + unmap(payload); + return; + } + + if (m_codeBlock->isConstantRegisterIndex(index)) { + move(Imm32(getConstantOperand(index).payload()), payload); + unmap(payload); + return; + } + + load32(payloadFor(index), payload); + unmap(payload); +} + +inline void JIT::emitLoad(const JSValue& v, RegisterID tag, RegisterID payload) +{ + move(Imm32(v.payload()), payload); + move(Imm32(v.tag()), tag); +} + +inline void JIT::emitLoad(int index, RegisterID tag, RegisterID payload, RegisterID base) +{ + ASSERT(tag != payload); + + if (base == callFrameRegister) { + ASSERT(payload != base); + emitLoadPayload(index, payload); + emitLoadTag(index, tag); + return; + } + + if (payload == base) { // avoid stomping base + load32(tagFor(index, base), tag); + load32(payloadFor(index, base), payload); + return; + } + + load32(payloadFor(index, base), payload); + load32(tagFor(index, base), tag); +} + +inline void JIT::emitLoad2(int index1, RegisterID tag1, RegisterID payload1, int index2, RegisterID tag2, RegisterID payload2) +{ + if (isMapped(index1)) { + emitLoad(index1, tag1, payload1); + emitLoad(index2, tag2, payload2); + return; + } + emitLoad(index2, tag2, payload2); + emitLoad(index1, tag1, payload1); +} + +inline void JIT::emitLoadDouble(int index, FPRegisterID value) +{ + if (m_codeBlock->isConstantRegisterIndex(index)) { + WriteBarrier& inConstantPool = m_codeBlock->constantRegister(index); + loadDouble(&inConstantPool, value); + } else + loadDouble(addressFor(index), value); +} + +inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value) +{ + if (m_codeBlock->isConstantRegisterIndex(index)) { + WriteBarrier& inConstantPool = m_codeBlock->constantRegister(index); + char* bytePointer = reinterpret_cast(&inConstantPool); + convertInt32ToDouble(AbsoluteAddress(bytePointer + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), value); + } else + convertInt32ToDouble(payloadFor(index), value); +} + +inline void JIT::emitStore(int index, RegisterID tag, RegisterID payload, RegisterID base) +{ + store32(payload, payloadFor(index, base)); + store32(tag, tagFor(index, base)); +} + +inline void JIT::emitStoreInt32(int index, RegisterID payload, bool indexIsInt32) +{ + store32(payload, payloadFor(index, callFrameRegister)); + if (!indexIsInt32) + store32(TrustedImm32(JSValue::Int32Tag), tagFor(index, callFrameRegister)); +} + +inline void JIT::emitStoreAndMapInt32(int index, RegisterID tag, RegisterID payload, bool indexIsInt32, size_t opcodeLength) +{ + emitStoreInt32(index, payload, indexIsInt32); + map(m_bytecodeOffset + opcodeLength, index, tag, payload); +} + +inline void JIT::emitStoreInt32(int index, TrustedImm32 payload, bool indexIsInt32) +{ + store32(payload, payloadFor(index, callFrameRegister)); + if (!indexIsInt32) + store32(TrustedImm32(JSValue::Int32Tag), tagFor(index, callFrameRegister)); +} + +inline void JIT::emitStoreCell(int index, RegisterID payload, bool indexIsCell) +{ + store32(payload, payloadFor(index, callFrameRegister)); + if (!indexIsCell) + store32(TrustedImm32(JSValue::CellTag), tagFor(index, callFrameRegister)); +} + +inline void JIT::emitStoreBool(int index, RegisterID payload, bool indexIsBool) +{ + store32(payload, payloadFor(index, callFrameRegister)); + if (!indexIsBool) + store32(TrustedImm32(JSValue::BooleanTag), tagFor(index, callFrameRegister)); +} + +inline void JIT::emitStoreDouble(int index, FPRegisterID value) +{ + storeDouble(value, addressFor(index)); +} + +inline void JIT::emitStore(int index, const JSValue constant, RegisterID base) +{ + store32(Imm32(constant.payload()), payloadFor(index, base)); + store32(Imm32(constant.tag()), tagFor(index, base)); +} + +ALWAYS_INLINE void JIT::emitInitRegister(unsigned dst) +{ + emitStore(dst, jsUndefined()); +} + +inline bool JIT::isLabeled(unsigned bytecodeOffset) +{ + for (size_t numberOfJumpTargets = m_codeBlock->numberOfJumpTargets(); m_jumpTargetIndex != numberOfJumpTargets; ++m_jumpTargetIndex) { + unsigned jumpTarget = m_codeBlock->jumpTarget(m_jumpTargetIndex); + if (jumpTarget == bytecodeOffset) + return true; + if (jumpTarget > bytecodeOffset) + return false; + } + return false; +} + +inline void JIT::map(unsigned bytecodeOffset, int virtualRegisterIndex, RegisterID tag, RegisterID payload) +{ + if (isLabeled(bytecodeOffset)) + return; + + m_mappedBytecodeOffset = bytecodeOffset; + m_mappedVirtualRegisterIndex = virtualRegisterIndex; + m_mappedTag = tag; + m_mappedPayload = payload; + + ASSERT(!canBeOptimized() || m_mappedPayload == regT0); + ASSERT(!canBeOptimized() || m_mappedTag == regT1); +} + +inline void JIT::unmap(RegisterID registerID) +{ + if (m_mappedTag == registerID) + m_mappedTag = (RegisterID)-1; + else if (m_mappedPayload == registerID) + m_mappedPayload = (RegisterID)-1; +} + +inline void JIT::unmap() +{ + m_mappedBytecodeOffset = (unsigned)-1; + m_mappedVirtualRegisterIndex = JSStack::ReturnPC; + m_mappedTag = (RegisterID)-1; + m_mappedPayload = (RegisterID)-1; +} + +inline bool JIT::isMapped(int virtualRegisterIndex) +{ + if (m_mappedBytecodeOffset != m_bytecodeOffset) + return false; + if (m_mappedVirtualRegisterIndex != virtualRegisterIndex) + return false; + return true; +} + +inline bool JIT::getMappedPayload(int virtualRegisterIndex, RegisterID& payload) +{ + if (m_mappedBytecodeOffset != m_bytecodeOffset) + return false; + if (m_mappedVirtualRegisterIndex != virtualRegisterIndex) + return false; + if (m_mappedPayload == (RegisterID)-1) + return false; + payload = m_mappedPayload; + return true; +} + +inline bool JIT::getMappedTag(int virtualRegisterIndex, RegisterID& tag) +{ + if (m_mappedBytecodeOffset != m_bytecodeOffset) + return false; + if (m_mappedVirtualRegisterIndex != virtualRegisterIndex) + return false; + if (m_mappedTag == (RegisterID)-1) + return false; + tag = m_mappedTag; + return true; +} + +inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex) +{ + if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) { + if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex)) + addSlowCase(jump()); + else + addSlowCase(emitJumpIfNotJSCell(virtualRegisterIndex)); + } +} + +inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex, RegisterID tag) +{ + if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) { + if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex)) + addSlowCase(jump()); + else + addSlowCase(branch32(NotEqual, tag, TrustedImm32(JSValue::CellTag))); + } +} + +ALWAYS_INLINE bool JIT::isOperandConstantImmediateInt(unsigned src) +{ + return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32(); +} + +ALWAYS_INLINE bool JIT::getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant) +{ + if (isOperandConstantImmediateInt(op1)) { + constant = getConstantOperand(op1).asInt32(); + op = op2; + return true; + } + + if (isOperandConstantImmediateInt(op2)) { + constant = getConstantOperand(op2).asInt32(); + op = op1; + return true; + } + + return false; +} + +#else // USE(JSVALUE32_64) + +/* Deprecated: Please use JITStubCall instead. */ + +ALWAYS_INLINE void JIT::emitGetJITStubArg(unsigned argumentNumber, RegisterID dst) +{ + unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX; + peek64(dst, argumentStackOffset); +} + +ALWAYS_INLINE void JIT::killLastResultRegister() +{ + m_lastResultBytecodeRegister = std::numeric_limits::max(); +} + +// get arg puts an arg from the SF register array into a h/w register +ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, RegisterID dst) +{ + ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. + + // TODO: we want to reuse values that are already in registers if we can - add a register allocator! + if (m_codeBlock->isConstantRegisterIndex(src)) { + JSValue value = m_codeBlock->getConstant(src); + if (!value.isNumber()) + move(TrustedImm64(JSValue::encode(value)), dst); + else + move(Imm64(JSValue::encode(value)), dst); + killLastResultRegister(); + return; + } + + if (src == m_lastResultBytecodeRegister && m_codeBlock->isTemporaryRegisterIndex(src) && !atJumpTarget()) { + // The argument we want is already stored in eax + if (dst != cachedResultRegister) + move(cachedResultRegister, dst); + killLastResultRegister(); + return; + } + + load64(Address(callFrameRegister, src * sizeof(Register)), dst); + killLastResultRegister(); +} + +ALWAYS_INLINE void JIT::emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2) +{ + if (src2 == m_lastResultBytecodeRegister) { + emitGetVirtualRegister(src2, dst2); + emitGetVirtualRegister(src1, dst1); + } else { + emitGetVirtualRegister(src1, dst1); + emitGetVirtualRegister(src2, dst2); + } +} + +ALWAYS_INLINE int32_t JIT::getConstantOperandImmediateInt(unsigned src) +{ + return getConstantOperand(src).asInt32(); +} + +ALWAYS_INLINE bool JIT::isOperandConstantImmediateInt(unsigned src) +{ + return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32(); +} + +ALWAYS_INLINE void JIT::emitPutVirtualRegister(unsigned dst, RegisterID from) +{ + store64(from, Address(callFrameRegister, dst * sizeof(Register))); + m_lastResultBytecodeRegister = (from == cachedResultRegister) ? static_cast(dst) : std::numeric_limits::max(); +} + +ALWAYS_INLINE void JIT::emitInitRegister(unsigned dst) +{ + store64(TrustedImm64(JSValue::encode(jsUndefined())), Address(callFrameRegister, dst * sizeof(Register))); +} + +ALWAYS_INLINE JIT::Jump JIT::emitJumpIfJSCell(RegisterID reg) +{ + return branchTest64(Zero, reg, tagMaskRegister); +} + +ALWAYS_INLINE JIT::Jump JIT::emitJumpIfBothJSCells(RegisterID reg1, RegisterID reg2, RegisterID scratch) +{ + move(reg1, scratch); + or64(reg2, scratch); + return emitJumpIfJSCell(scratch); +} + +ALWAYS_INLINE void JIT::emitJumpSlowCaseIfJSCell(RegisterID reg) +{ + addSlowCase(emitJumpIfJSCell(reg)); +} + +ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotJSCell(RegisterID reg) +{ + return branchTest64(NonZero, reg, tagMaskRegister); +} + +ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg) +{ + addSlowCase(emitJumpIfNotJSCell(reg)); +} + +ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, int vReg) +{ + if (!m_codeBlock->isKnownNotImmediate(vReg)) + emitJumpSlowCaseIfNotJSCell(reg); +} + +inline void JIT::emitLoadDouble(int index, FPRegisterID value) +{ + if (m_codeBlock->isConstantRegisterIndex(index)) { + WriteBarrier& inConstantPool = m_codeBlock->constantRegister(index); + loadDouble(&inConstantPool, value); + } else + loadDouble(addressFor(index), value); +} + +inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value) +{ + if (m_codeBlock->isConstantRegisterIndex(index)) { + ASSERT(isOperandConstantImmediateInt(index)); + convertInt32ToDouble(Imm32(getConstantOperand(index).asInt32()), value); + } else + convertInt32ToDouble(addressFor(index), value); +} + +ALWAYS_INLINE JIT::Jump JIT::emitJumpIfImmediateInteger(RegisterID reg) +{ + return branch64(AboveOrEqual, reg, tagTypeNumberRegister); +} + +ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateInteger(RegisterID reg) +{ + return branch64(Below, reg, tagTypeNumberRegister); +} + +ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateIntegers(RegisterID reg1, RegisterID reg2, RegisterID scratch) +{ + move(reg1, scratch); + and64(reg2, scratch); + return emitJumpIfNotImmediateInteger(scratch); +} + +ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateInteger(RegisterID reg) +{ + addSlowCase(emitJumpIfNotImmediateInteger(reg)); +} + +ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateIntegers(RegisterID reg1, RegisterID reg2, RegisterID scratch) +{ + addSlowCase(emitJumpIfNotImmediateIntegers(reg1, reg2, scratch)); +} + +ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateNumber(RegisterID reg) +{ + addSlowCase(emitJumpIfNotImmediateNumber(reg)); +} + +ALWAYS_INLINE void JIT::emitFastArithReTagImmediate(RegisterID src, RegisterID dest) +{ + emitFastArithIntToImmNoCheck(src, dest); +} + +// operand is int32_t, must have been zero-extended if register is 64-bit. +ALWAYS_INLINE void JIT::emitFastArithIntToImmNoCheck(RegisterID src, RegisterID dest) +{ + if (src != dest) + move(src, dest); + or64(tagTypeNumberRegister, dest); +} + +ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg) +{ + or32(TrustedImm32(static_cast(ValueFalse)), reg); +} + +#endif // USE(JSVALUE32_64) + +} // namespace JSC + +#endif // ENABLE(JIT) + +#endif diff --git a/Source/JavaScriptCore/jit/JITInlines.h b/Source/JavaScriptCore/jit/JITInlines.h deleted file mode 100644 index e6f95b94c..000000000 --- a/Source/JavaScriptCore/jit/JITInlines.h +++ /dev/null @@ -1,1013 +0,0 @@ -/* - * 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 - * 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 JITInlines_h -#define JITInlines_h - - -#if ENABLE(JIT) - -namespace JSC { - -ALWAYS_INLINE bool JIT::isOperandConstantImmediateDouble(unsigned src) -{ - return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isDouble(); -} - -ALWAYS_INLINE JSValue JIT::getConstantOperand(unsigned src) -{ - ASSERT(m_codeBlock->isConstantRegisterIndex(src)); - return m_codeBlock->getConstant(src); -} - -ALWAYS_INLINE void JIT::emitPutCellToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry) -{ -#if USE(JSVALUE32_64) - store32(TrustedImm32(JSValue::CellTag), tagFor(entry, callFrameRegister)); - store32(from, payloadFor(entry, callFrameRegister)); -#else - store64(from, addressFor(entry, callFrameRegister)); -#endif -} - -ALWAYS_INLINE void JIT::emitPutIntToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry) -{ -#if USE(JSVALUE32_64) - store32(TrustedImm32(Int32Tag), intTagFor(entry, callFrameRegister)); - store32(from, intPayloadFor(entry, callFrameRegister)); -#else - store64(from, addressFor(entry, callFrameRegister)); -#endif -} - -ALWAYS_INLINE void JIT::emitPutToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry) -{ -#if USE(JSVALUE32_64) - storePtr(from, payloadFor(entry, callFrameRegister)); -#else - store64(from, addressFor(entry, callFrameRegister)); -#endif -} - -ALWAYS_INLINE void JIT::emitPutImmediateToCallFrameHeader(void* value, JSStack::CallFrameHeaderEntry entry) -{ - storePtr(TrustedImmPtr(value), Address(callFrameRegister, entry * sizeof(Register))); -} - -ALWAYS_INLINE void JIT::emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from) -{ - loadPtr(Address(from, entry * sizeof(Register)), to); -#if USE(JSVALUE64) - killLastResultRegister(); -#endif -} - -ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader32(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from) -{ - load32(Address(from, entry * sizeof(Register)), to); -#if USE(JSVALUE64) - killLastResultRegister(); -#endif -} - -#if USE(JSVALUE64) -ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader64(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from) -{ - load64(Address(from, entry * sizeof(Register)), to); - killLastResultRegister(); -} -#endif - -ALWAYS_INLINE void JIT::emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures) -{ - failures.append(branchPtr(NotEqual, Address(src, JSCell::structureOffset()), TrustedImmPtr(m_globalData->stringStructure.get()))); - failures.append(branch32(NotEqual, MacroAssembler::Address(src, ThunkHelpers::jsStringLengthOffset()), TrustedImm32(1))); - loadPtr(MacroAssembler::Address(src, ThunkHelpers::jsStringValueOffset()), dst); - failures.append(branchTest32(Zero, dst)); - loadPtr(MacroAssembler::Address(dst, ThunkHelpers::stringImplFlagsOffset()), regT1); - loadPtr(MacroAssembler::Address(dst, ThunkHelpers::stringImplDataOffset()), dst); - - JumpList is16Bit; - JumpList cont8Bit; - is16Bit.append(branchTest32(Zero, regT1, TrustedImm32(ThunkHelpers::stringImpl8BitFlag()))); - load8(MacroAssembler::Address(dst, 0), dst); - cont8Bit.append(jump()); - is16Bit.link(this); - load16(MacroAssembler::Address(dst, 0), dst); - cont8Bit.link(this); -} - -ALWAYS_INLINE JIT::Call JIT::emitNakedCall(CodePtr function) -{ - ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. - - Call nakedCall = nearCall(); - m_calls.append(CallRecord(nakedCall, m_bytecodeOffset, function.executableAddress())); - return nakedCall; -} - -ALWAYS_INLINE bool JIT::atJumpTarget() -{ - while (m_jumpTargetsPosition < m_codeBlock->numberOfJumpTargets() && m_codeBlock->jumpTarget(m_jumpTargetsPosition) <= m_bytecodeOffset) { - if (m_codeBlock->jumpTarget(m_jumpTargetsPosition) == m_bytecodeOffset) - return true; - ++m_jumpTargetsPosition; - } - return false; -} - -#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL - -ALWAYS_INLINE void JIT::beginUninterruptedSequence(int insnSpace, int constSpace) -{ -#if CPU(ARM_TRADITIONAL) -#ifndef NDEBUG - // Ensure the label after the sequence can also fit - insnSpace += sizeof(ARMWord); - constSpace += sizeof(uint64_t); -#endif - - ensureSpace(insnSpace, constSpace); - -#elif CPU(SH4) -#ifndef NDEBUG - insnSpace += sizeof(SH4Word); - constSpace += sizeof(uint64_t); -#endif - - m_assembler.ensureSpace(insnSpace + m_assembler.maxInstructionSize + 2, constSpace + 8); -#endif - -#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL -#ifndef NDEBUG - m_uninterruptedInstructionSequenceBegin = label(); - m_uninterruptedConstantSequenceBegin = sizeOfConstantPool(); -#endif -#endif -} - -ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace, int dst) -{ - UNUSED_PARAM(dst); -#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL - /* There are several cases when the uninterrupted sequence is larger than - * maximum required offset for pathing the same sequence. Eg.: if in a - * uninterrupted sequence the last macroassembler's instruction is a stub - * call, it emits store instruction(s) which should not be included in the - * calculation of length of uninterrupted sequence. So, the insnSpace and - * constSpace should be upper limit instead of hard limit. - */ -#if CPU(SH4) - if ((dst > 15) || (dst < -16)) { - insnSpace += 8; - constSpace += 2; - } - - if (((dst >= -16) && (dst < 0)) || ((dst > 7) && (dst <= 15))) - insnSpace += 8; -#endif - ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) <= insnSpace); - ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin <= constSpace); -#endif -} - -#endif - -#if CPU(ARM) - -ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg) -{ - move(linkRegister, reg); -} - -ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg) -{ - move(reg, linkRegister); -} - -ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) -{ - loadPtr(address, linkRegister); -} -#elif CPU(SH4) - -ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg) -{ - m_assembler.stspr(reg); -} - -ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg) -{ - m_assembler.ldspr(reg); -} - -ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) -{ - loadPtrLinkReg(address); -} - -#elif CPU(MIPS) - -ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg) -{ - move(returnAddressRegister, reg); -} - -ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg) -{ - move(reg, returnAddressRegister); -} - -ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) -{ - loadPtr(address, returnAddressRegister); -} - -#else // CPU(X86) || CPU(X86_64) - -ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg) -{ - pop(reg); -} - -ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg) -{ - push(reg); -} - -ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) -{ - push(address); -} - -#endif - -ALWAYS_INLINE void JIT::restoreArgumentReference() -{ - move(stackPointerRegister, firstArgumentRegister); - poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); -} - -ALWAYS_INLINE void JIT::updateTopCallFrame() -{ - ASSERT(static_cast(m_bytecodeOffset) >= 0); - if (m_bytecodeOffset) { -#if USE(JSVALUE32_64) - storePtr(TrustedImmPtr(m_codeBlock->instructions().begin() + m_bytecodeOffset + 1), intTagFor(JSStack::ArgumentCount)); -#else - store32(TrustedImm32(m_bytecodeOffset + 1), intTagFor(JSStack::ArgumentCount)); -#endif - } - storePtr(callFrameRegister, &m_globalData->topCallFrame); -} - -ALWAYS_INLINE void JIT::restoreArgumentReferenceForTrampoline() -{ -#if CPU(X86) - // Within a trampoline the return address will be on the stack at this point. - addPtr(TrustedImm32(sizeof(void*)), stackPointerRegister, firstArgumentRegister); -#elif CPU(ARM) - move(stackPointerRegister, firstArgumentRegister); -#elif CPU(SH4) - move(stackPointerRegister, firstArgumentRegister); -#endif - // In the trampoline on x86-64, the first argument register is not overwritten. -} - -ALWAYS_INLINE JIT::Jump JIT::checkStructure(RegisterID reg, Structure* structure) -{ - return branchPtr(NotEqual, Address(reg, JSCell::structureOffset()), TrustedImmPtr(structure)); -} - -ALWAYS_INLINE void JIT::linkSlowCaseIfNotJSCell(Vector::iterator& iter, int vReg) -{ - if (!m_codeBlock->isKnownNotImmediate(vReg)) - linkSlowCase(iter); -} - -ALWAYS_INLINE void JIT::addSlowCase(Jump jump) -{ - ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. - - m_slowCases.append(SlowCaseEntry(jump, m_bytecodeOffset)); -} - -ALWAYS_INLINE void JIT::addSlowCase(JumpList jumpList) -{ - ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. - - const JumpList::JumpVector& jumpVector = jumpList.jumps(); - size_t size = jumpVector.size(); - for (size_t i = 0; i < size; ++i) - m_slowCases.append(SlowCaseEntry(jumpVector[i], m_bytecodeOffset)); -} - -ALWAYS_INLINE void JIT::addSlowCase() -{ - ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. - - Jump emptyJump; // Doing it this way to make Windows happy. - m_slowCases.append(SlowCaseEntry(emptyJump, m_bytecodeOffset)); -} - -ALWAYS_INLINE void JIT::addJump(Jump jump, int relativeOffset) -{ - ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. - - m_jmpTable.append(JumpTable(jump, m_bytecodeOffset + relativeOffset)); -} - -ALWAYS_INLINE void JIT::emitJumpSlowToHot(Jump jump, int relativeOffset) -{ - ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. - - jump.linkTo(m_labels[m_bytecodeOffset + relativeOffset], this); -} - -ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotObject(RegisterID structureReg) -{ - return branch8(Below, Address(structureReg, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType)); -} - -ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotType(RegisterID baseReg, RegisterID scratchReg, JSType type) -{ - loadPtr(Address(baseReg, JSCell::structureOffset()), scratchReg); - return branch8(NotEqual, Address(scratchReg, Structure::typeInfoTypeOffset()), TrustedImm32(type)); -} - -#if ENABLE(SAMPLING_FLAGS) -ALWAYS_INLINE void JIT::setSamplingFlag(int32_t flag) -{ - ASSERT(flag >= 1); - ASSERT(flag <= 32); - or32(TrustedImm32(1u << (flag - 1)), AbsoluteAddress(SamplingFlags::addressOfFlags())); -} - -ALWAYS_INLINE void JIT::clearSamplingFlag(int32_t flag) -{ - ASSERT(flag >= 1); - ASSERT(flag <= 32); - and32(TrustedImm32(~(1u << (flag - 1))), AbsoluteAddress(SamplingFlags::addressOfFlags())); -} -#endif - -#if ENABLE(SAMPLING_COUNTERS) -ALWAYS_INLINE void JIT::emitCount(AbstractSamplingCounter& counter, int32_t count) -{ - add64(TrustedImm32(count), AbsoluteAddress(counter.addressOfCounter())); -} -#endif - -#if ENABLE(OPCODE_SAMPLING) -#if CPU(X86_64) -ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction) -{ - move(TrustedImmPtr(m_interpreter->sampler()->sampleSlot()), X86Registers::ecx); - storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), X86Registers::ecx); -} -#else -ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction) -{ - storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), m_interpreter->sampler()->sampleSlot()); -} -#endif -#endif - -#if ENABLE(CODEBLOCK_SAMPLING) -#if CPU(X86_64) -ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock) -{ - move(TrustedImmPtr(m_interpreter->sampler()->codeBlockSlot()), X86Registers::ecx); - storePtr(TrustedImmPtr(codeBlock), X86Registers::ecx); -} -#else -ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock) -{ - storePtr(TrustedImmPtr(codeBlock), m_interpreter->sampler()->codeBlockSlot()); -} -#endif -#endif - -ALWAYS_INLINE bool JIT::isOperandConstantImmediateChar(unsigned src) -{ - return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isString() && asString(getConstantOperand(src).asCell())->length() == 1; -} - -template inline void JIT::emitAllocateBasicJSObject(StructureType structure, RegisterID result, RegisterID storagePtr) -{ - size_t size = ClassType::allocationSize(INLINE_STORAGE_CAPACITY); - MarkedAllocator* allocator = 0; - if (destructorType == MarkedBlock::Normal) - allocator = &m_globalData->heap.allocatorForObjectWithNormalDestructor(size); - else if (destructorType == MarkedBlock::ImmortalStructure) - allocator = &m_globalData->heap.allocatorForObjectWithImmortalStructureDestructor(size); - else - allocator = &m_globalData->heap.allocatorForObjectWithoutDestructor(size); - loadPtr(&allocator->m_freeList.head, result); - addSlowCase(branchTestPtr(Zero, result)); - - // remove the object from the free list - loadPtr(Address(result), storagePtr); - storePtr(storagePtr, &allocator->m_freeList.head); - - // initialize the object's structure - storePtr(structure, Address(result, JSCell::structureOffset())); - - // initialize the object's property storage pointer - storePtr(TrustedImmPtr(0), Address(result, JSObject::butterflyOffset())); -} - -template inline void JIT::emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch) -{ - emitAllocateBasicJSObject(structure, result, scratch); -} - -#if ENABLE(VALUE_PROFILER) -inline void JIT::emitValueProfilingSite(ValueProfile* valueProfile) -{ - ASSERT(shouldEmitProfiling()); - ASSERT(valueProfile); - - const RegisterID value = regT0; -#if USE(JSVALUE32_64) - const RegisterID valueTag = regT1; -#endif - const RegisterID scratch = regT3; - - if (ValueProfile::numberOfBuckets == 1) { - // We're in a simple configuration: only one bucket, so we can just do a direct - // store. -#if USE(JSVALUE64) - store64(value, valueProfile->m_buckets); -#else - EncodedValueDescriptor* descriptor = bitwise_cast(valueProfile->m_buckets); - store32(value, &descriptor->asBits.payload); - store32(valueTag, &descriptor->asBits.tag); -#endif - return; - } - - if (m_randomGenerator.getUint32() & 1) - add32(TrustedImm32(1), bucketCounterRegister); - else - add32(TrustedImm32(3), bucketCounterRegister); - and32(TrustedImm32(ValueProfile::bucketIndexMask), bucketCounterRegister); - move(TrustedImmPtr(valueProfile->m_buckets), scratch); -#if USE(JSVALUE64) - store64(value, BaseIndex(scratch, bucketCounterRegister, TimesEight)); -#elif USE(JSVALUE32_64) - store32(value, BaseIndex(scratch, bucketCounterRegister, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); - store32(valueTag, BaseIndex(scratch, bucketCounterRegister, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); -#endif -} - -inline void JIT::emitValueProfilingSite(unsigned bytecodeOffset) -{ - if (!shouldEmitProfiling()) - return; - emitValueProfilingSite(m_codeBlock->valueProfileForBytecodeOffset(bytecodeOffset)); -} - -inline void JIT::emitValueProfilingSite() -{ - emitValueProfilingSite(m_bytecodeOffset); -} -#endif // ENABLE(VALUE_PROFILER) - -inline void JIT::emitArrayProfilingSite(RegisterID structureAndIndexingType, RegisterID scratch, ArrayProfile* arrayProfile) -{ - UNUSED_PARAM(scratch); // We had found this scratch register useful here before, so I will keep it for now. - - RegisterID structure = structureAndIndexingType; - RegisterID indexingType = structureAndIndexingType; - - if (canBeOptimized()) - storePtr(structure, arrayProfile->addressOfLastSeenStructure()); - - load8(Address(structure, Structure::indexingTypeOffset()), indexingType); -} - -inline void JIT::emitArrayProfilingSiteForBytecodeIndex(RegisterID structureAndIndexingType, RegisterID scratch, unsigned bytecodeIndex) -{ -#if ENABLE(VALUE_PROFILER) - emitArrayProfilingSite(structureAndIndexingType, scratch, m_codeBlock->getOrAddArrayProfile(bytecodeIndex)); -#else - UNUSED_PARAM(bytecodeIndex); - emitArrayProfilingSite(structureAndIndexingType, scratch, 0); -#endif -} - -inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfile) -{ -#if ENABLE(VALUE_PROFILER) - store8(TrustedImm32(1), arrayProfile->addressOfMayStoreToHole()); -#else - UNUSED_PARAM(arrayProfile); -#endif -} - -static inline bool arrayProfileSaw(ArrayModes arrayModes, IndexingType capability) -{ -#if ENABLE(VALUE_PROFILER) - return arrayModesInclude(arrayModes, capability); -#else - UNUSED_PARAM(arrayModes); - UNUSED_PARAM(capability); - return false; -#endif -} - -inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile) -{ -#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) - -inline void JIT::emitLoadTag(int index, RegisterID tag) -{ - RegisterID mappedTag; - if (getMappedTag(index, mappedTag)) { - move(mappedTag, tag); - unmap(tag); - return; - } - - if (m_codeBlock->isConstantRegisterIndex(index)) { - move(Imm32(getConstantOperand(index).tag()), tag); - unmap(tag); - return; - } - - load32(tagFor(index), tag); - unmap(tag); -} - -inline void JIT::emitLoadPayload(int index, RegisterID payload) -{ - RegisterID mappedPayload; - if (getMappedPayload(index, mappedPayload)) { - move(mappedPayload, payload); - unmap(payload); - return; - } - - if (m_codeBlock->isConstantRegisterIndex(index)) { - move(Imm32(getConstantOperand(index).payload()), payload); - unmap(payload); - return; - } - - load32(payloadFor(index), payload); - unmap(payload); -} - -inline void JIT::emitLoad(const JSValue& v, RegisterID tag, RegisterID payload) -{ - move(Imm32(v.payload()), payload); - move(Imm32(v.tag()), tag); -} - -inline void JIT::emitLoad(int index, RegisterID tag, RegisterID payload, RegisterID base) -{ - ASSERT(tag != payload); - - if (base == callFrameRegister) { - ASSERT(payload != base); - emitLoadPayload(index, payload); - emitLoadTag(index, tag); - return; - } - - if (payload == base) { // avoid stomping base - load32(tagFor(index, base), tag); - load32(payloadFor(index, base), payload); - return; - } - - load32(payloadFor(index, base), payload); - load32(tagFor(index, base), tag); -} - -inline void JIT::emitLoad2(int index1, RegisterID tag1, RegisterID payload1, int index2, RegisterID tag2, RegisterID payload2) -{ - if (isMapped(index1)) { - emitLoad(index1, tag1, payload1); - emitLoad(index2, tag2, payload2); - return; - } - emitLoad(index2, tag2, payload2); - emitLoad(index1, tag1, payload1); -} - -inline void JIT::emitLoadDouble(int index, FPRegisterID value) -{ - if (m_codeBlock->isConstantRegisterIndex(index)) { - WriteBarrier& inConstantPool = m_codeBlock->constantRegister(index); - loadDouble(&inConstantPool, value); - } else - loadDouble(addressFor(index), value); -} - -inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value) -{ - if (m_codeBlock->isConstantRegisterIndex(index)) { - WriteBarrier& inConstantPool = m_codeBlock->constantRegister(index); - char* bytePointer = reinterpret_cast(&inConstantPool); - convertInt32ToDouble(AbsoluteAddress(bytePointer + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), value); - } else - convertInt32ToDouble(payloadFor(index), value); -} - -inline void JIT::emitStore(int index, RegisterID tag, RegisterID payload, RegisterID base) -{ - store32(payload, payloadFor(index, base)); - store32(tag, tagFor(index, base)); -} - -inline void JIT::emitStoreInt32(int index, RegisterID payload, bool indexIsInt32) -{ - store32(payload, payloadFor(index, callFrameRegister)); - if (!indexIsInt32) - store32(TrustedImm32(JSValue::Int32Tag), tagFor(index, callFrameRegister)); -} - -inline void JIT::emitStoreAndMapInt32(int index, RegisterID tag, RegisterID payload, bool indexIsInt32, size_t opcodeLength) -{ - emitStoreInt32(index, payload, indexIsInt32); - map(m_bytecodeOffset + opcodeLength, index, tag, payload); -} - -inline void JIT::emitStoreInt32(int index, TrustedImm32 payload, bool indexIsInt32) -{ - store32(payload, payloadFor(index, callFrameRegister)); - if (!indexIsInt32) - store32(TrustedImm32(JSValue::Int32Tag), tagFor(index, callFrameRegister)); -} - -inline void JIT::emitStoreCell(int index, RegisterID payload, bool indexIsCell) -{ - store32(payload, payloadFor(index, callFrameRegister)); - if (!indexIsCell) - store32(TrustedImm32(JSValue::CellTag), tagFor(index, callFrameRegister)); -} - -inline void JIT::emitStoreBool(int index, RegisterID payload, bool indexIsBool) -{ - store32(payload, payloadFor(index, callFrameRegister)); - if (!indexIsBool) - store32(TrustedImm32(JSValue::BooleanTag), tagFor(index, callFrameRegister)); -} - -inline void JIT::emitStoreDouble(int index, FPRegisterID value) -{ - storeDouble(value, addressFor(index)); -} - -inline void JIT::emitStore(int index, const JSValue constant, RegisterID base) -{ - store32(Imm32(constant.payload()), payloadFor(index, base)); - store32(Imm32(constant.tag()), tagFor(index, base)); -} - -ALWAYS_INLINE void JIT::emitInitRegister(unsigned dst) -{ - emitStore(dst, jsUndefined()); -} - -inline bool JIT::isLabeled(unsigned bytecodeOffset) -{ - for (size_t numberOfJumpTargets = m_codeBlock->numberOfJumpTargets(); m_jumpTargetIndex != numberOfJumpTargets; ++m_jumpTargetIndex) { - unsigned jumpTarget = m_codeBlock->jumpTarget(m_jumpTargetIndex); - if (jumpTarget == bytecodeOffset) - return true; - if (jumpTarget > bytecodeOffset) - return false; - } - return false; -} - -inline void JIT::map(unsigned bytecodeOffset, int virtualRegisterIndex, RegisterID tag, RegisterID payload) -{ - if (isLabeled(bytecodeOffset)) - return; - - m_mappedBytecodeOffset = bytecodeOffset; - m_mappedVirtualRegisterIndex = virtualRegisterIndex; - m_mappedTag = tag; - m_mappedPayload = payload; - - ASSERT(!canBeOptimized() || m_mappedPayload == regT0); - ASSERT(!canBeOptimized() || m_mappedTag == regT1); -} - -inline void JIT::unmap(RegisterID registerID) -{ - if (m_mappedTag == registerID) - m_mappedTag = (RegisterID)-1; - else if (m_mappedPayload == registerID) - m_mappedPayload = (RegisterID)-1; -} - -inline void JIT::unmap() -{ - m_mappedBytecodeOffset = (unsigned)-1; - m_mappedVirtualRegisterIndex = JSStack::ReturnPC; - m_mappedTag = (RegisterID)-1; - m_mappedPayload = (RegisterID)-1; -} - -inline bool JIT::isMapped(int virtualRegisterIndex) -{ - if (m_mappedBytecodeOffset != m_bytecodeOffset) - return false; - if (m_mappedVirtualRegisterIndex != virtualRegisterIndex) - return false; - return true; -} - -inline bool JIT::getMappedPayload(int virtualRegisterIndex, RegisterID& payload) -{ - if (m_mappedBytecodeOffset != m_bytecodeOffset) - return false; - if (m_mappedVirtualRegisterIndex != virtualRegisterIndex) - return false; - if (m_mappedPayload == (RegisterID)-1) - return false; - payload = m_mappedPayload; - return true; -} - -inline bool JIT::getMappedTag(int virtualRegisterIndex, RegisterID& tag) -{ - if (m_mappedBytecodeOffset != m_bytecodeOffset) - return false; - if (m_mappedVirtualRegisterIndex != virtualRegisterIndex) - return false; - if (m_mappedTag == (RegisterID)-1) - return false; - tag = m_mappedTag; - return true; -} - -inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex) -{ - if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) { - if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex)) - addSlowCase(jump()); - else - addSlowCase(emitJumpIfNotJSCell(virtualRegisterIndex)); - } -} - -inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex, RegisterID tag) -{ - if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) { - if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex)) - addSlowCase(jump()); - else - addSlowCase(branch32(NotEqual, tag, TrustedImm32(JSValue::CellTag))); - } -} - -ALWAYS_INLINE bool JIT::isOperandConstantImmediateInt(unsigned src) -{ - return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32(); -} - -ALWAYS_INLINE bool JIT::getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant) -{ - if (isOperandConstantImmediateInt(op1)) { - constant = getConstantOperand(op1).asInt32(); - op = op2; - return true; - } - - if (isOperandConstantImmediateInt(op2)) { - constant = getConstantOperand(op2).asInt32(); - op = op1; - return true; - } - - return false; -} - -#else // USE(JSVALUE32_64) - -/* Deprecated: Please use JITStubCall instead. */ - -ALWAYS_INLINE void JIT::emitGetJITStubArg(unsigned argumentNumber, RegisterID dst) -{ - unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX; - peek64(dst, argumentStackOffset); -} - -ALWAYS_INLINE void JIT::killLastResultRegister() -{ - m_lastResultBytecodeRegister = std::numeric_limits::max(); -} - -// get arg puts an arg from the SF register array into a h/w register -ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, RegisterID dst) -{ - ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set. - - // TODO: we want to reuse values that are already in registers if we can - add a register allocator! - if (m_codeBlock->isConstantRegisterIndex(src)) { - JSValue value = m_codeBlock->getConstant(src); - if (!value.isNumber()) - move(TrustedImm64(JSValue::encode(value)), dst); - else - move(Imm64(JSValue::encode(value)), dst); - killLastResultRegister(); - return; - } - - if (src == m_lastResultBytecodeRegister && m_codeBlock->isTemporaryRegisterIndex(src) && !atJumpTarget()) { - // The argument we want is already stored in eax - if (dst != cachedResultRegister) - move(cachedResultRegister, dst); - killLastResultRegister(); - return; - } - - load64(Address(callFrameRegister, src * sizeof(Register)), dst); - killLastResultRegister(); -} - -ALWAYS_INLINE void JIT::emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2) -{ - if (src2 == m_lastResultBytecodeRegister) { - emitGetVirtualRegister(src2, dst2); - emitGetVirtualRegister(src1, dst1); - } else { - emitGetVirtualRegister(src1, dst1); - emitGetVirtualRegister(src2, dst2); - } -} - -ALWAYS_INLINE int32_t JIT::getConstantOperandImmediateInt(unsigned src) -{ - return getConstantOperand(src).asInt32(); -} - -ALWAYS_INLINE bool JIT::isOperandConstantImmediateInt(unsigned src) -{ - return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32(); -} - -ALWAYS_INLINE void JIT::emitPutVirtualRegister(unsigned dst, RegisterID from) -{ - store64(from, Address(callFrameRegister, dst * sizeof(Register))); - m_lastResultBytecodeRegister = (from == cachedResultRegister) ? static_cast(dst) : std::numeric_limits::max(); -} - -ALWAYS_INLINE void JIT::emitInitRegister(unsigned dst) -{ - store64(TrustedImm64(JSValue::encode(jsUndefined())), Address(callFrameRegister, dst * sizeof(Register))); -} - -ALWAYS_INLINE JIT::Jump JIT::emitJumpIfJSCell(RegisterID reg) -{ - return branchTest64(Zero, reg, tagMaskRegister); -} - -ALWAYS_INLINE JIT::Jump JIT::emitJumpIfBothJSCells(RegisterID reg1, RegisterID reg2, RegisterID scratch) -{ - move(reg1, scratch); - or64(reg2, scratch); - return emitJumpIfJSCell(scratch); -} - -ALWAYS_INLINE void JIT::emitJumpSlowCaseIfJSCell(RegisterID reg) -{ - addSlowCase(emitJumpIfJSCell(reg)); -} - -ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotJSCell(RegisterID reg) -{ - return branchTest64(NonZero, reg, tagMaskRegister); -} - -ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg) -{ - addSlowCase(emitJumpIfNotJSCell(reg)); -} - -ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, int vReg) -{ - if (!m_codeBlock->isKnownNotImmediate(vReg)) - emitJumpSlowCaseIfNotJSCell(reg); -} - -inline void JIT::emitLoadDouble(int index, FPRegisterID value) -{ - if (m_codeBlock->isConstantRegisterIndex(index)) { - WriteBarrier& inConstantPool = m_codeBlock->constantRegister(index); - loadDouble(&inConstantPool, value); - } else - loadDouble(addressFor(index), value); -} - -inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value) -{ - if (m_codeBlock->isConstantRegisterIndex(index)) { - ASSERT(isOperandConstantImmediateInt(index)); - convertInt32ToDouble(Imm32(getConstantOperand(index).asInt32()), value); - } else - convertInt32ToDouble(addressFor(index), value); -} - -ALWAYS_INLINE JIT::Jump JIT::emitJumpIfImmediateInteger(RegisterID reg) -{ - return branch64(AboveOrEqual, reg, tagTypeNumberRegister); -} - -ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateInteger(RegisterID reg) -{ - return branch64(Below, reg, tagTypeNumberRegister); -} - -ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateIntegers(RegisterID reg1, RegisterID reg2, RegisterID scratch) -{ - move(reg1, scratch); - and64(reg2, scratch); - return emitJumpIfNotImmediateInteger(scratch); -} - -ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateInteger(RegisterID reg) -{ - addSlowCase(emitJumpIfNotImmediateInteger(reg)); -} - -ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateIntegers(RegisterID reg1, RegisterID reg2, RegisterID scratch) -{ - addSlowCase(emitJumpIfNotImmediateIntegers(reg1, reg2, scratch)); -} - -ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateNumber(RegisterID reg) -{ - addSlowCase(emitJumpIfNotImmediateNumber(reg)); -} - -ALWAYS_INLINE void JIT::emitFastArithReTagImmediate(RegisterID src, RegisterID dest) -{ - emitFastArithIntToImmNoCheck(src, dest); -} - -// operand is int32_t, must have been zero-extended if register is 64-bit. -ALWAYS_INLINE void JIT::emitFastArithIntToImmNoCheck(RegisterID src, RegisterID dest) -{ - if (src != dest) - move(src, dest); - or64(tagTypeNumberRegister, dest); -} - -ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg) -{ - or32(TrustedImm32(static_cast(ValueFalse)), reg); -} - -#endif // USE(JSVALUE32_64) - -} // namespace JSC - -#endif // ENABLE(JIT) - -#endif // JITInlines_h - diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp index 3053918b8..4fb9d8cd5 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp @@ -29,9 +29,9 @@ #include "JIT.h" #include "Arguments.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.h" #include "Heap.h" -#include "JITInlines.h" +#include "JITInlineMethods.h" #include "JITStubCall.h" #include "JSArray.h" #include "JSCell.h" @@ -1952,7 +1952,6 @@ 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); } @@ -1964,7 +1963,6 @@ 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); } @@ -1973,7 +1971,6 @@ 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 23361c099..9c5d260ab 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 "JITInlines.h" +#include "JITInlineMethods.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 3110be38c..6362598f4 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 "JITInlines.h" +#include "JITInlineMethods.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,12 +120,6 @@ 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; @@ -154,26 +148,11 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done)); } -JIT::JumpList JIT::emitDoubleGetByVal(Instruction*, PatchableJump& badType) +JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType) { JumpList slowCases; - 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)); + badType = patchableBranch32(NotEqual, regT2, TrustedImm32(ContiguousShape)); loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2); slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength()))); load64(BaseIndex(regT2, regT1, TimesEight), regT0); @@ -325,12 +304,6 @@ 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; @@ -352,49 +325,24 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) emitWriteBarrier(regT0, regT3, regT1, regT3, ShouldFilterImmediates, WriteBarrierForPropertyAccess); } -template -JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) +JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) { unsigned value = currentInstruction[3].u.operand; ArrayProfile* profile = currentInstruction[4].u.arrayProfile; - JumpList slowCases; - - badType = patchableBranch32(NotEqual, regT2, TrustedImm32(indexingShape)); + badType = patchableBranch32(NotEqual, regT2, TrustedImm32(ContiguousShape)); loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2); Jump outOfBounds = branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength())); Label storeResult = label(); emitGetVirtualRegister(value, regT3); - 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; - } + store64(regT3, BaseIndex(regT2, regT1, TimesEight)); Jump done = jump(); outOfBounds.link(this); + JumpList slowCases; slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfVectorLength()))); emitArrayProfileStoreToHoleSpecialCase(profile); @@ -446,23 +394,12 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector -JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) +JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) { unsigned value = currentInstruction[3].u.operand; ArrayProfile* profile = currentInstruction[4].u.arrayProfile; @@ -332,30 +303,8 @@ JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction Label storeResult = label(); emitLoad(value, regT1, regT0); - 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; - } - + store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); Jump done = jump(); outOfBounds.link(this); @@ -415,23 +364,12 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, VectorgetJITType() == 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 @@ -2233,21 +2228,21 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_array) { STUB_INIT_STACK_FRAME(stackFrame); - return constructArray(stackFrame.callFrame, stackFrame.args[2].arrayAllocationProfile(), reinterpret_cast(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()]), stackFrame.args[1].int32()); + return constructArray(stackFrame.callFrame, reinterpret_cast(&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.args[1].arrayAllocationProfile(), stackFrame.callFrame->lexicalGlobalObject(), stackFrame.args[0].jsValue()); + return constructArrayWithSizeQuirk(stackFrame.callFrame, 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.args[2].arrayAllocationProfile(), stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32()); + return constructArray(stackFrame.callFrame, stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32()); } DEFINE_STUB_FUNCTION(void, op_init_global_const_check) @@ -2475,7 +2470,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 3bf13bbdf..5761236b1 100644 --- a/Source/JavaScriptCore/jit/JITStubs.h +++ b/Source/JavaScriptCore/jit/JITStubs.h @@ -45,7 +45,6 @@ namespace JSC { struct StructureStubInfo; - class ArrayAllocationProfile; class CodeBlock; class ExecutablePool; class FunctionExecutable; @@ -86,7 +85,6 @@ namespace JSC { ReturnAddressPtr returnAddress() { return ReturnAddressPtr(asPointer); } ResolveOperations* resolveOperations() { return static_cast(asPointer); } PutToBaseOperation* putToBaseOperation() { return static_cast(asPointer); } - ArrayAllocationProfile* arrayAllocationProfile() { return static_cast(asPointer); } }; struct TrampolineStructure { diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp index 07a05b0c9..b8cf49da6 100644 --- a/Source/JavaScriptCore/jsc.cpp +++ b/Source/JavaScriptCore/jsc.cpp @@ -22,10 +22,10 @@ #include "config.h" -#include "ButterflyInlines.h" +#include "ButterflyInlineMethods.h" #include "BytecodeGenerator.h" #include "Completion.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.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(), 0); + JSArray* array = constructEmptyArray(globalExec()); 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 8a578ffac..ba44bf404 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->updateAllValueProfilePredictions(); + codeBlock->updateAllPredictions(); 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, pc[4].u.arrayAllocationProfile, bitwise_cast(&LLINT_OP(2)), pc[3].u.operand)); + LLINT_RETURN(constructArray(exec, bitwise_cast(&LLINT_OP(2)), pc[3].u.operand)); } LLINT_SLOW_PATH_DECL(slow_path_new_array_with_size) { LLINT_BEGIN(); - LLINT_RETURN(constructArrayWithSizeQuirk(exec, pc[3].u.arrayAllocationProfile, exec->lexicalGlobalObject(), LLINT_OP_C(2).jsValue())); + LLINT_RETURN(constructArrayWithSizeQuirk(exec, exec->lexicalGlobalObject(), LLINT_OP_C(2).jsValue())); } LLINT_SLOW_PATH_DECL(slow_path_new_array_buffer) { LLINT_BEGIN(); - LLINT_RETURN(constructArray(exec, pc[4].u.arrayAllocationProfile, exec->codeBlock()->constantBuffer(pc[2].u.operand), pc[3].u.operand)); + LLINT_RETURN(constructArray(exec, 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 00d5c4f6f..ba5b67df4 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm @@ -88,13 +88,10 @@ else end # Constant for reasoning about butterflies. -const IsArray = 1 -const IndexingShapeMask = 30 -const NoIndexingShape = 0 -const Int32Shape = 20 -const DoubleShape = 22 -const ContiguousShape = 26 -const ArrayStorageShape = 28 +const IsArray = 1 +const IndexingShapeMask = 30 +const ContiguousShape = 26 +const ArrayStorageShape = 28 const SlowPutArrayStorageShape = 30 # Type constants. @@ -465,19 +462,19 @@ end _llint_op_new_array: traceExecution() callSlowPath(_llint_slow_path_new_array) - dispatch(5) + dispatch(4) _llint_op_new_array_with_size: traceExecution() callSlowPath(_llint_slow_path_new_array_with_size) - dispatch(4) + dispatch(3) _llint_op_new_array_buffer: traceExecution() callSlowPath(_llint_slow_path_new_array_buffer) - dispatch(5) + dispatch(4) _llint_op_new_regexp: diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm index e3ef909f5..ffb146247 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm @@ -1185,9 +1185,7 @@ _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 @@ -1195,16 +1193,6 @@ _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 @@ -1214,7 +1202,6 @@ _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 @@ -1283,24 +1270,6 @@ _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 @@ -1312,42 +1281,26 @@ _llint_op_put_by_val: loadConstantOrVariablePayload(t0, Int32Tag, t3, .opPutByValSlow) loadp JSObject::m_butterfly[t1], t0 andi IndexingShapeMask, t2 - 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) + bineq t2, ContiguousShape, .opPutByValNotContiguous -.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) + 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) -.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) +.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 .opPutByValNotContiguous: bineq t2, ArrayStorageShape, .opPutByValSlow diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm index d8a293337..c9900b343 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm @@ -1025,9 +1025,7 @@ _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) @@ -1036,16 +1034,6 @@ _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 @@ -1121,24 +1109,6 @@ _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) @@ -1151,38 +1121,25 @@ _llint_op_put_by_val: sxi2q t3, t3 loadp JSObject::m_butterfly[t1], t0 andi IndexingShapeMask, t2 - bineq t2, Int32Shape, .opPutByValNotInt32 - contiguousPutByVal( - macro (operand, scratch, address) - loadConstantOrVariable(operand, scratch) - bpb scratch, tagTypeNumber, .opPutByValSlow - storep scratch, address - end) - -.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) + + 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) + +.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 .opPutByValNotContiguous: bineq t2, ArrayStorageShape, .opPutByValSlow diff --git a/Source/JavaScriptCore/offlineasm/x86.rb b/Source/JavaScriptCore/offlineasm/x86.rb index f78b43912..67cbd14b0 100644 --- a/Source/JavaScriptCore/offlineasm/x86.rb +++ b/Source/JavaScriptCore/offlineasm/x86.rb @@ -764,16 +764,11 @@ 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)}" - 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 + $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}" + $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}" + isUnordered.lower("X86") when "bdneq" handleX86DoubleBranch("jne", :normal) when "bdgt" @@ -787,19 +782,14 @@ 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)}" - 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 + $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") when "bdgtun" handleX86DoubleBranch("jb", :reverse) when "bdgtequn" @@ -1125,7 +1115,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 "movd %xmm7, #{operands[2].x86Operand(:int)}" + $asm.puts "movsd %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/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h index 8ae991422..7961d4bc8 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; + 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(globalData.heap)) Arguments(callFrame); + arguments->finishCreation(callFrame); + return arguments; + } + + static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame, InlineCallFrame* inlineCallFrame) + { + Arguments* arguments = new (NotNull, allocateCell(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*); - static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame) + 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& argument(size_t); + void allocateSlowArguments(); + + void init(CallFrame*); + + WriteBarrier 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* m_registers; + OwnArrayPtr > m_registerArray; + + OwnArrayPtr m_slowArguments; + + WriteBarrier m_callee; + }; + + Arguments* asArguments(JSValue); + + inline Arguments* asArguments(JSValue value) { - Arguments* arguments = new (NotNull, allocateCell(globalData.heap)) Arguments(callFrame); - arguments->finishCreation(callFrame); - return arguments; + ASSERT(asObject(value)->inherits(&Arguments::s_info)); + return static_cast(asObject(value)); } - - static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame, InlineCallFrame* inlineCallFrame) + + inline Arguments::Arguments(CallFrame* callFrame) + : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) { - Arguments* arguments = new (NotNull, allocateCell(globalData.heap)) Arguments(callFrame); - arguments->finishCreation(callFrame, inlineCallFrame); - return arguments; } - enum { MaxArguments = 0x10000 }; + inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) + : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) + { + } -private: - enum NoParametersType { NoParameters }; - - Arguments(CallFrame*); - Arguments(CallFrame*, NoParametersType); - - void tearOffForInlineCallFrame(JSGlobalData& globalData, Register*, InlineCallFrame*); + 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); + } + } -public: - static const ClassInfo s_info; + inline bool Arguments::tryDeleteArgument(size_t argument) + { + if (!isArgument(argument)) + return false; + allocateSlowArguments(); + m_slowArguments[argument].status = SlowArgument::Deleted; + return true; + } - static void visitChildren(JSCell*, SlotVisitor&); + 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; + } - void fillArgList(ExecState*, MarkedArgumentBuffer&); + inline JSValue Arguments::tryGetArgument(size_t argument) + { + if (!isArgument(argument)) + return JSValue(); + return this->argument(argument).get(); + } - uint32_t length(ExecState* exec) const + inline bool Arguments::isDeletedArgument(size_t argument) { - if (UNLIKELY(m_overrodeLength)) - return get(exec, exec->propertyNames().length).toUInt32(exec); - return m_numArguments; + if (argument >= m_numArguments) + return false; + if (!m_slowArguments) + return false; + if (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 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; } - -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& argument(size_t); - void allocateSlowArguments(); - - void init(CallFrame*); - - WriteBarrier 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* m_registers; - OwnArrayPtr > m_registerArray; - - OwnArrayPtr m_slowArguments; - - WriteBarrier m_callee; -}; - -Arguments* asArguments(JSValue); - -inline Arguments* asArguments(JSValue value) -{ - ASSERT(asObject(value)->inherits(&Arguments::s_info)); - return static_cast(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 WriteBarrierBase& 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 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& 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(callFrame->callee()); - m_numArguments = callFrame->argumentCount(); - m_registers = reinterpret_cast*>(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(m_numArguments, symbolTable->parameterCount()); - for (size_t i = 0; i < count; ++i) - m_slowArguments[i] = slowArguments[i]; + + inline void Arguments::finishCreation(CallFrame* callFrame) + { + Base::finishCreation(callFrame->globalData()); + ASSERT(inherits(&s_info)); + + JSFunction* callee = jsCast(callFrame->callee()); + m_numArguments = callFrame->argumentCount(); + m_registers = reinterpret_cast*>(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(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); } - // 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*>(callFrame->registers()) + inlineCallFrame->stackOffset; - m_callee.set(callFrame->globalData(), this, callee); - m_overrodeLength = false; - m_overrodeCallee = false; - m_overrodeCaller = false; - m_isStrictMode = jsCast(inlineCallFrame->executable.get())->isStrictMode(); - ASSERT(!jsCast(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); -} + 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*>(callFrame->registers()) + inlineCallFrame->stackOffset; + m_callee.set(callFrame->globalData(), this, callee); + m_overrodeLength = false; + m_overrodeCallee = false; + m_overrodeCaller = false; + m_isStrictMode = jsCast(inlineCallFrame->executable.get())->isStrictMode(); + ASSERT(!jsCast(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 a3fce45f2..5c2cd7167 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -25,8 +25,8 @@ #include "ArrayConstructor.h" #include "ArrayPrototype.h" -#include "ButterflyInlines.h" -#include "CopiedSpaceInlines.h" +#include "ButterflyInlineMethods.h" +#include "CopiedSpaceInlineMethods.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, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length) +JSObject* constructArrayWithSizeQuirk(ExecState* exec, JSGlobalObject* globalObject, JSValue length) { if (!length.isNumber()) - return constructArray(exec, profile, globalObject, &length, 1); + return constructArray(exec, 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, profile, globalObject, n); + return constructEmptyArray(exec, 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, 0, globalObject, args.at(0)); + return constructArrayWithSizeQuirk(exec, globalObject, args.at(0)); // otherwise the array is constructed with the arguments in it - return constructArray(exec, 0, globalObject, args); + return constructArray(exec, 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 96860b0fc..dcbf0a1b3 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(*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(*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*, ArrayAllocationProfile*, JSGlobalObject*, JSValue); + JSObject* constructArrayWithSizeQuirk(ExecState*, JSGlobalObject*, JSValue); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index cc847d8ff..6975dc778 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -24,10 +24,10 @@ #include "config.h" #include "ArrayPrototype.h" -#include "ButterflyInlines.h" +#include "ButterflyInlineMethods.h" #include "CachedCall.h" #include "CodeBlock.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.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, 0); + JSArray* arr = constructEmptyArray(exec); 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, 0); + JSArray* resObj = constructEmptyArray(exec); 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, 0)); + return JSValue::encode(constructEmptyArray(exec)); unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length); @@ -748,7 +748,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) deleteCount = static_cast(deleteDouble); } - JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount); + JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), 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, 0); + JSArray* resultArray = constructEmptyArray(exec); 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, 0, length); + JSArray* resultArray = constructEmptyArray(exec, length); unsigned k = 0; if (callType == CallTypeJS && isJSArray(thisObj)) { JSFunction* f = jsCast(function); diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.h b/Source/JavaScriptCore/runtime/ArrayPrototype.h index 2b83d39b7..b33021121 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 4b8d53f7e..cb93aea8a 100644 --- a/Source/JavaScriptCore/runtime/Butterfly.h +++ b/Source/JavaScriptCore/runtime/Butterfly.h @@ -88,18 +88,12 @@ public: template T* indexingPayload() { return reinterpret_cast(this); } ArrayStorage* arrayStorage() { return indexingPayload(); } - WriteBarrier* contiguousInt32() { return indexingPayload >(); } - double* contiguousDouble() { return indexingPayload(); } WriteBarrier* contiguous() { return indexingPayload >(); } static Butterfly* fromContiguous(WriteBarrier* contiguous) { return reinterpret_cast(contiguous); } - static Butterfly* fromContiguous(double* contiguous) - { - return reinterpret_cast(contiguous); - } static ptrdiff_t offsetOfPropertyStorage() { return -static_cast(sizeof(IndexingHeader)); } static int indexOfPropertyStorage() diff --git a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h b/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h new file mode 100644 index 000000000..86a836bef --- /dev/null +++ b/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h @@ -0,0 +1,179 @@ +/* + * 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 ButterflyInlineMethods_h +#define ButterflyInlineMethods_h + +#include "ArrayStorage.h" +#include "Butterfly.h" +#include "CopiedSpaceInlineMethods.h" +#include "CopyVisitor.h" +#include "JSGlobalData.h" +#include "Structure.h" + +namespace JSC { + +inline Butterfly* Butterfly::createUninitialized(JSGlobalData& globalData, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) +{ + void* temp; + size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); + if (!globalData.heap.tryAllocateStorage(size, &temp)) + CRASH(); + Butterfly* result = fromBase(temp, preCapacity, propertyCapacity); + return result; +} + +inline Butterfly* Butterfly::create(JSGlobalData& globalData, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes) +{ + Butterfly* result = createUninitialized( + globalData, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); + if (hasIndexingHeader) + *result->indexingHeader() = indexingHeader; + return result; +} + +inline Butterfly* Butterfly::create(JSGlobalData& globalData, Structure* structure) +{ + return create(globalData, 0, structure->outOfLineCapacity(), hasIndexingHeader(structure->indexingType()), IndexingHeader(), 0); +} + +inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) +{ + Butterfly* result = fromBase( + visitor.allocateNewSpace(totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)), + preCapacity, propertyCapacity); + return result; +} + +inline void* Butterfly::base(Structure* structure) +{ + return base(indexingHeader()->preCapacity(structure), structure->outOfLineCapacity()); +} + +inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity) +{ + ASSERT(newPropertyCapacity > oldPropertyCapacity); + Butterfly* result = createUninitialized( + globalData, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); + memcpy( + result->propertyStorage() - oldPropertyCapacity, + propertyStorage() - oldPropertyCapacity, + totalSize(0, oldPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)); + return result; +} + +inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity) +{ + return growPropertyStorage( + globalData, indexingHeader()->preCapacity(structure), oldPropertyCapacity, + hasIndexingHeader(structure->indexingType()), + indexingHeader()->indexingPayloadSizeInBytes(structure), newPropertyCapacity); +} + +inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, Structure* oldStructure, size_t newPropertyCapacity) +{ + return growPropertyStorage( + globalData, oldStructure, oldStructure->outOfLineCapacity(), newPropertyCapacity); +} + +inline Butterfly* Butterfly::growArrayRight(JSGlobalData& globalData, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes) +{ + ASSERT_UNUSED(oldStructure, !indexingHeader()->preCapacity(oldStructure)); + ASSERT_UNUSED(oldStructure, hadIndexingHeader == hasIndexingHeader(oldStructure->indexingType())); + void* theBase = base(0, propertyCapacity); + size_t oldSize = totalSize(0, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes); + size_t newSize = totalSize(0, propertyCapacity, true, newIndexingPayloadSizeInBytes); + if (!globalData.heap.tryReallocateStorage(&theBase, oldSize, newSize)) + return 0; + return fromBase(theBase, 0, propertyCapacity); +} + +inline Butterfly* Butterfly::growArrayRight(JSGlobalData& globalData, Structure* oldStructure, size_t newIndexingPayloadSizeInBytes) +{ + return growArrayRight( + globalData, oldStructure, oldStructure->outOfLineCapacity(), + hasIndexingHeader(oldStructure->indexingType()), + indexingHeader()->indexingPayloadSizeInBytes(oldStructure), newIndexingPayloadSizeInBytes); +} + +inline Butterfly* Butterfly::resizeArray(JSGlobalData& globalData, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes) +{ + Butterfly* result = createUninitialized( + globalData, newPreCapacity, propertyCapacity, newHasIndexingHeader, newIndexingPayloadSizeInBytes); + // FIXME: This could be made much more efficient if we used the property size, + // not the capacity. + void* to = result->propertyStorage() - propertyCapacity; + void* from = propertyStorage() - propertyCapacity; + size_t size = std::min( + totalSize(0, propertyCapacity, oldHasIndexingHeader, oldIndexingPayloadSizeInBytes), + totalSize(0, propertyCapacity, newHasIndexingHeader, newIndexingPayloadSizeInBytes)); + memcpy(to, from, size); + return result; +} + +inline Butterfly* Butterfly::resizeArray(JSGlobalData& globalData, Structure* structure, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes) +{ + bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType()); + return resizeArray( + globalData, structure->outOfLineCapacity(), hasIndexingHeader, + indexingHeader()->indexingPayloadSizeInBytes(structure), newPreCapacity, + hasIndexingHeader, newIndexingPayloadSizeInBytes); +} + +inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots) +{ + ASSERT(hasArrayStorage(structure->indexingType())); + ASSERT(numberOfSlots <= indexingHeader()->preCapacity(structure)); + unsigned propertyCapacity = structure->outOfLineCapacity(); + // FIXME: It would probably be wise to rewrite this as a loop since (1) we know in which + // direction we're moving memory so we don't need the extra check of memmove and (2) we're + // moving a small amount of memory in the common case so the throughput of memmove won't + // amortize the overhead of calling it. And no, we cannot rely on the C++ compiler to + // inline memmove (particularly since the size argument is likely to be variable), nor can + // we rely on the compiler to recognize the ordering of the pointer arguments (since + // propertyCapacity is variable and could cause wrap-around as far as the compiler knows). + memmove( + propertyStorage() - numberOfSlots - propertyCapacity, + propertyStorage() - propertyCapacity, + sizeof(EncodedJSValue) * propertyCapacity + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); + return IndexingHeader::fromEndOf(propertyStorage() - numberOfSlots)->butterfly(); +} + +inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots) +{ + ASSERT(hasArrayStorage(structure->indexingType())); + unsigned propertyCapacity = structure->outOfLineCapacity(); + // FIXME: See comment in unshift(), above. + memmove( + propertyStorage() - propertyCapacity + numberOfSlots, + propertyStorage() - propertyCapacity, + sizeof(EncodedJSValue) * propertyCapacity + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); + return IndexingHeader::fromEndOf(propertyStorage() + numberOfSlots)->butterfly(); +} + +} // namespace JSC + +#endif // ButterflyInlineMethods_h + diff --git a/Source/JavaScriptCore/runtime/ButterflyInlines.h b/Source/JavaScriptCore/runtime/ButterflyInlines.h deleted file mode 100644 index 9167497a4..000000000 --- a/Source/JavaScriptCore/runtime/ButterflyInlines.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * 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 ButterflyInlines_h -#define ButterflyInlines_h - -#include "ArrayStorage.h" -#include "Butterfly.h" -#include "CopiedSpaceInlines.h" -#include "CopyVisitor.h" -#include "JSGlobalData.h" -#include "Structure.h" - -namespace JSC { - -inline Butterfly* Butterfly::createUninitialized(JSGlobalData& globalData, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) -{ - void* temp; - size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - if (!globalData.heap.tryAllocateStorage(size, &temp)) - CRASH(); - Butterfly* result = fromBase(temp, preCapacity, propertyCapacity); - return result; -} - -inline Butterfly* Butterfly::create(JSGlobalData& globalData, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes) -{ - Butterfly* result = createUninitialized( - globalData, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - if (hasIndexingHeader) - *result->indexingHeader() = indexingHeader; - return result; -} - -inline Butterfly* Butterfly::create(JSGlobalData& globalData, Structure* structure) -{ - return create(globalData, 0, structure->outOfLineCapacity(), hasIndexingHeader(structure->indexingType()), IndexingHeader(), 0); -} - -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(size), - preCapacity, propertyCapacity); - return result; -} - -inline void* Butterfly::base(Structure* structure) -{ - return base(indexingHeader()->preCapacity(structure), structure->outOfLineCapacity()); -} - -inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity) -{ - ASSERT(newPropertyCapacity > oldPropertyCapacity); - Butterfly* result = createUninitialized( - globalData, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - memcpy( - result->propertyStorage() - oldPropertyCapacity, - propertyStorage() - oldPropertyCapacity, - totalSize(0, oldPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)); - return result; -} - -inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity) -{ - return growPropertyStorage( - globalData, indexingHeader()->preCapacity(structure), oldPropertyCapacity, - hasIndexingHeader(structure->indexingType()), - indexingHeader()->indexingPayloadSizeInBytes(structure), newPropertyCapacity); -} - -inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, Structure* oldStructure, size_t newPropertyCapacity) -{ - return growPropertyStorage( - globalData, oldStructure, oldStructure->outOfLineCapacity(), newPropertyCapacity); -} - -inline Butterfly* Butterfly::growArrayRight(JSGlobalData& globalData, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes) -{ - ASSERT_UNUSED(oldStructure, !indexingHeader()->preCapacity(oldStructure)); - ASSERT_UNUSED(oldStructure, hadIndexingHeader == hasIndexingHeader(oldStructure->indexingType())); - void* theBase = base(0, propertyCapacity); - size_t oldSize = totalSize(0, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes); - size_t newSize = totalSize(0, propertyCapacity, true, newIndexingPayloadSizeInBytes); - if (!globalData.heap.tryReallocateStorage(&theBase, oldSize, newSize)) - return 0; - return fromBase(theBase, 0, propertyCapacity); -} - -inline Butterfly* Butterfly::growArrayRight(JSGlobalData& globalData, Structure* oldStructure, size_t newIndexingPayloadSizeInBytes) -{ - return growArrayRight( - globalData, oldStructure, oldStructure->outOfLineCapacity(), - hasIndexingHeader(oldStructure->indexingType()), - indexingHeader()->indexingPayloadSizeInBytes(oldStructure), newIndexingPayloadSizeInBytes); -} - -inline Butterfly* Butterfly::resizeArray(JSGlobalData& globalData, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes) -{ - Butterfly* result = createUninitialized( - globalData, newPreCapacity, propertyCapacity, newHasIndexingHeader, newIndexingPayloadSizeInBytes); - // FIXME: This could be made much more efficient if we used the property size, - // not the capacity. - void* to = result->propertyStorage() - propertyCapacity; - void* from = propertyStorage() - propertyCapacity; - size_t size = std::min( - totalSize(0, propertyCapacity, oldHasIndexingHeader, oldIndexingPayloadSizeInBytes), - totalSize(0, propertyCapacity, newHasIndexingHeader, newIndexingPayloadSizeInBytes)); - memcpy(to, from, size); - return result; -} - -inline Butterfly* Butterfly::resizeArray(JSGlobalData& globalData, Structure* structure, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes) -{ - bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType()); - return resizeArray( - globalData, structure->outOfLineCapacity(), hasIndexingHeader, - indexingHeader()->indexingPayloadSizeInBytes(structure), newPreCapacity, - hasIndexingHeader, newIndexingPayloadSizeInBytes); -} - -inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots) -{ - ASSERT(hasArrayStorage(structure->indexingType())); - ASSERT(numberOfSlots <= indexingHeader()->preCapacity(structure)); - unsigned propertyCapacity = structure->outOfLineCapacity(); - // FIXME: It would probably be wise to rewrite this as a loop since (1) we know in which - // direction we're moving memory so we don't need the extra check of memmove and (2) we're - // moving a small amount of memory in the common case so the throughput of memmove won't - // amortize the overhead of calling it. And no, we cannot rely on the C++ compiler to - // inline memmove (particularly since the size argument is likely to be variable), nor can - // we rely on the compiler to recognize the ordering of the pointer arguments (since - // propertyCapacity is variable and could cause wrap-around as far as the compiler knows). - memmove( - propertyStorage() - numberOfSlots - propertyCapacity, - propertyStorage() - propertyCapacity, - sizeof(EncodedJSValue) * propertyCapacity + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); - return IndexingHeader::fromEndOf(propertyStorage() - numberOfSlots)->butterfly(); -} - -inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots) -{ - ASSERT(hasArrayStorage(structure->indexingType())); - unsigned propertyCapacity = structure->outOfLineCapacity(); - // FIXME: See comment in unshift(), above. - memmove( - propertyStorage() - propertyCapacity + numberOfSlots, - propertyStorage() - propertyCapacity, - sizeof(EncodedJSValue) * propertyCapacity + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); - return IndexingHeader::fromEndOf(propertyStorage() + numberOfSlots)->butterfly(); -} - -} // namespace JSC - -#endif // ButterflyInlines_h - diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp index 068919528..4de760e49 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.cpp +++ b/Source/JavaScriptCore/runtime/CodeCache.cpp @@ -36,6 +36,7 @@ namespace JSC { CodeCache::CodeCache() + : m_randomGenerator(static_cast(randomNumber() * UINT32_MAX)) { } @@ -66,9 +67,9 @@ UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, Executa CodeBlockKey key = makeCodeBlockKey(source, CacheTypes::codeType, strictness); bool storeInCache = false; if (debuggerMode == DebuggerOff && profilerMode == ProfilerOff) { - const Strong* result = m_cachedCodeBlocks.find(key); - if (result) { - UnlinkedCodeBlockType* unlinkedCode = jsCast(result->get()); + CodeBlockIndicesMap::iterator result = m_cachedCodeBlockIndices.find(key); + if (result != m_cachedCodeBlockIndices.end()) { + UnlinkedCodeBlockType* unlinkedCode = jsCast(m_cachedCodeBlocks[result->value].second.get()); unsigned firstLine = source.firstLine() + unlinkedCode->firstLine(); executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount()); return unlinkedCode; @@ -90,8 +91,14 @@ UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, Executa if (error.m_type != ParserError::ErrorNone) return 0; - if (storeInCache) - m_cachedCodeBlocks.add(key, Strong(globalData, unlinkedCode)); + 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; + } return unlinkedCode; } @@ -126,7 +133,6 @@ UnlinkedFunctionCodeBlock* CodeCache::generateFunctionCodeBlock(JSGlobalData& gl body->destroyData(); if (error.m_type != ParserError::ErrorNone) return 0; - m_cachedFunctionCode.add(result, Strong(globalData, result)); return result; } @@ -143,9 +149,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()); - const Strong* result = m_cachedGlobalFunctions.find(key); - if (result) - return result->get(); + GlobalFunctionIndicesMap::iterator result = m_cachedGlobalFunctionIndices.find(key); + if (result != m_cachedGlobalFunctionIndices.end()) + return m_cachedGlobalFunctions[result->value].second.get(); RefPtr program = parse(&globalData, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); if (!program) { @@ -167,13 +173,14 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlo UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&globalData, source, body); functionExecutable->m_nameValue.set(globalData, functionExecutable, jsString(&globalData, name.string())); - m_cachedGlobalFunctions.add(key, Strong(globalData, functionExecutable)); - return functionExecutable; -} + 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; -void CodeCache::usedFunctionCode(JSGlobalData& globalData, UnlinkedFunctionCodeBlock* codeBlock) -{ - m_cachedFunctionCode.add(codeBlock, Strong(globalData, codeBlock)); + return functionExecutable; } } diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h index 740aaa6df..4d4617189 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.h +++ b/Source/JavaScriptCore/runtime/CodeCache.h @@ -34,7 +34,6 @@ #include #include #include -#include #include namespace JSC { @@ -52,41 +51,6 @@ struct ParserError; class SourceCode; class SourceProvider; -template class Thingy { - typedef typename HashMap::iterator iterator; -public: - Thingy() - : m_randomGenerator((static_cast(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 m_map; - FixedArray, CacheSize> m_data; - WeakRandom m_randomGenerator; -}; - class CodeCache { public: static PassOwnPtr create() { return adoptPtr(new CodeCache); } @@ -95,12 +59,13 @@ 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 CodeBlockKey; + typedef HashMap CodeBlockIndicesMap; typedef std::pair GlobalFunctionKey; + typedef HashMap GlobalFunctionIndicesMap; private: CodeCache(); @@ -109,17 +74,18 @@ private: template 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, - kMaxFunctionCodeBlocks = 1024 + kMaxGlobalFunctionEntries = 1024 }; - Thingy, kMaxCodeBlockEntries> m_cachedCodeBlocks; - Thingy, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions; - Thingy, kMaxFunctionCodeBlocks> m_cachedFunctionCode; + FixedArray >, kMaxCodeBlockEntries> m_cachedCodeBlocks; + FixedArray >, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions; + WeakRandom m_randomGenerator; }; } diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 49a0e256d..20a2e2acb 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -620,17 +620,18 @@ void FunctionExecutable::clearCodeIfNotCompiling() clearCode(); } -void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling() +void FunctionExecutable::clearUnlinkedCodeIfNotCompiling() { if (isCompiling()) return; - m_unlinkedExecutable->clearCodeForRecompilation(); + m_unlinkedExecutable->clearCode(); } 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 98471b85b..74b4add75 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 clearUnlinkedCodeForRecompilationIfNotCompiling(); + void clearUnlinkedCodeIfNotCompiling(); 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 8e4390b1b..a4b2202c1 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->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), numBoundArgs); + JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructure(), numBoundArgs); if (!boundArgs) return JSValue::encode(throwOutOfMemoryError(exec)); diff --git a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h b/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h new file mode 100644 index 000000000..22785ce24 --- /dev/null +++ b/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IndexingHeaderInlineMethods_h +#define IndexingHeaderInlineMethods_h + +#include "ArrayStorage.h" +#include "IndexingHeader.h" +#include "Structure.h" + +namespace JSC { + +inline size_t IndexingHeader::preCapacity(Structure* structure) +{ + if (LIKELY(!hasArrayStorage(structure->indexingType()))) + return 0; + + return arrayStorage()->m_indexBias; +} + +inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure) +{ + switch (structure->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + return vectorLength() * sizeof(EncodedJSValue); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return ArrayStorage::sizeFor(arrayStorage()->vectorLength()); + + default: + ASSERT(!hasIndexedProperties(structure->indexingType())); + return 0; + } +} + +} // namespace JSC + +#endif // IndexingHeaderInlineMethods_h + diff --git a/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h b/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h deleted file mode 100644 index cfad1c8c2..000000000 --- a/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 IndexingHeaderInlines_h -#define IndexingHeaderInlines_h - -#include "ArrayStorage.h" -#include "IndexingHeader.h" -#include "Structure.h" - -namespace JSC { - -inline size_t IndexingHeader::preCapacity(Structure* structure) -{ - if (LIKELY(!hasArrayStorage(structure->indexingType()))) - return 0; - - return arrayStorage()->m_indexBias; -} - -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); - - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return ArrayStorage::sizeFor(arrayStorage()->vectorLength()); - - default: - ASSERT(!hasIndexedProperties(structure->indexingType())); - return 0; - } -} - -} // namespace JSC - -#endif // IndexingHeaderInlines_h - diff --git a/Source/JavaScriptCore/runtime/IndexingType.cpp b/Source/JavaScriptCore/runtime/IndexingType.cpp index dc2733ad1..7261847a2 100644 --- a/Source/JavaScriptCore/runtime/IndexingType.cpp +++ b/Source/JavaScriptCore/runtime/IndexingType.cpp @@ -31,46 +31,6 @@ 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]; @@ -79,12 +39,6 @@ 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; @@ -97,15 +51,6 @@ 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 ab253be1e..4bbe3cfa0 100644 --- a/Source/JavaScriptCore/runtime/IndexingType.h +++ b/Source/JavaScriptCore/runtime/IndexingType.h @@ -26,7 +26,6 @@ #ifndef IndexingType_h #define IndexingType_h -#include "SpeculatedType.h" #include namespace JSC { @@ -38,32 +37,21 @@ 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 UndecidedShape = 2; // Only useful for arrays. -static const IndexingType Int32Shape = 20; -static const IndexingType DoubleShape = 22; +static const IndexingType NoIndexingShape = 0; 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; @@ -72,17 +60,6 @@ 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 @@ -106,21 +83,6 @@ 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; @@ -143,12 +105,6 @@ 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 b8f5621af..fc6336463 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.h +++ b/Source/JavaScriptCore/runtime/JSActivation.h @@ -30,7 +30,7 @@ #define JSActivation_h #include "CodeBlock.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.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 4ba5cc2bd..d1ece1a36 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -24,14 +24,14 @@ #include "JSArray.h" #include "ArrayPrototype.h" -#include "ButterflyInlines.h" -#include "CachedCall.h" +#include "ButterflyInlineMethods.h" #include "CopiedSpace.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.h" +#include "CachedCall.h" #include "Error.h" #include "Executable.h" #include "GetterSetter.h" -#include "IndexingHeaderInlines.h" +#include "IndexingHeaderInlineMethods.h" #include "PropertyNameArray.h" #include "Reject.h" #include @@ -410,33 +410,25 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException exec, newLength, throwException, convertContiguousToArrayStorage(exec->globalData())); } - createInitialUndecided(exec->globalData(), newLength); + createInitialContiguous(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, countElements()))) { + && !isDenseEnoughForVector(newLength, countElementsInContiguous(m_butterfly)))) { return setLengthWithArrayStorage( exec, newLength, throwException, - ensureArrayStorage(exec->globalData())); + convertContiguousToArrayStorage(exec->globalData())); } if (newLength > m_butterfly->publicLength()) { - ensureLength(exec->globalData(), newLength); + ensureContiguousLength(exec->globalData(), newLength); return true; } - 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(); - } + for (unsigned i = m_butterfly->publicLength(); i-- > newLength;) + m_butterfly->contiguous()[i].clear(); m_butterfly->setPublicLength(newLength); return true; @@ -456,13 +448,6 @@ 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(); @@ -479,22 +464,6 @@ 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(); @@ -549,42 +518,10 @@ void JSArray::push(ExecState* exec, JSValue value) { switch (structure()->indexingType()) { case ArrayClass: { - createInitialUndecided(exec->globalData(), 0); - // Fall through. - } - - case ArrayWithUndecided: { - convertUndecidedForValue(exec->globalData(), value); - push(exec, value); - return; + putByIndexBeyondVectorLengthWithArrayStorage(exec, 0, value, true, createInitialArrayStorage(exec->globalData())); + break; } - 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(exec, length, value); - return; - } - case ArrayWithContiguous: { unsigned length = m_butterfly->publicLength(); ASSERT(length <= m_butterfly->vectorLength()); @@ -601,42 +538,10 @@ void JSArray::push(ExecState* exec, JSValue value) return; } - putByIndexBeyondVectorLengthWithoutAttributes(exec, length, value); + putByIndexBeyondVectorLengthContiguousWithoutAttributes(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(exec, length, value); - break; - } - case ArrayWithSlowPutArrayStorage: { unsigned oldLength = length(); if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true)) { @@ -742,11 +647,6 @@ 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); @@ -754,7 +654,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, ensureArrayStorage(exec->globalData())); + return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData())); unsigned end = oldLength - count; for (unsigned i = startIndex; i < end; ++i) { @@ -768,7 +668,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, ensureArrayStorage(exec->globalData())); + return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(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 @@ -782,41 +682,6 @@ 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()); @@ -875,25 +740,23 @@ 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, ensureArrayStorage(exec->globalData())); + return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData())); - ensureLength(exec->globalData(), oldLength + count); + ensureContiguousLength(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, ensureArrayStorage(exec->globalData())); + return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData())); m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v); } @@ -905,31 +768,6 @@ 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()); @@ -940,20 +778,6 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd } } -static int compareNumbersForQSortWithInt32(const void* a, const void* b) -{ - int32_t ia = static_cast(a)->asInt32(); - int32_t ib = static_cast(b)->asInt32(); - return ia - ib; -} - -static int compareNumbersForQSortWithDouble(const void* a, const void* b) -{ - double da = *static_cast(a); - double db = *static_cast(b); - return (da > db) - (da < db); -} - static int compareNumbersForQSort(const void* a, const void* b) { double da = static_cast(a)->asNumber(); @@ -971,7 +795,7 @@ static int compareByStringPairForQSort(const void* a, const void* b) template void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) { - ASSERT(indexingType == ArrayWithInt32 || indexingType == ArrayWithDouble || indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage); + ASSERT(indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage); unsigned lengthNotIncludingUndefined; unsigned newRelevantLength; @@ -990,19 +814,11 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy return; bool allValuesAreNumbers = true; - switch (indexingType) { - case ArrayWithInt32: - case ArrayWithDouble: - break; - - default: - for (size_t i = 0; i < newRelevantLength; ++i) { - if (!data[i].isNumber()) { - allValuesAreNumbers = false; - break; - } + for (size_t i = 0; i < newRelevantLength; ++i) { + if (!data[i].isNumber()) { + allValuesAreNumbers = false; + break; } - break; } if (!allValuesAreNumbers) @@ -1011,23 +827,7 @@ 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. - int (*compare)(const void*, const void*); - switch (indexingType) { - case ArrayWithInt32: - compare = compareNumbersForQSortWithInt32; - break; - - case ArrayWithDouble: - compare = compareNumbersForQSortWithDouble; - ASSERT(sizeof(WriteBarrier) == sizeof(double)); - break; - - default: - compare = compareNumbersForQSort; - break; - } - - qsort(data, newRelevantLength, sizeof(WriteBarrier), compare); + qsort(data, newRelevantLength, sizeof(WriteBarrier), compareNumbersForQSort); return; } @@ -1039,14 +839,6 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal case ArrayClass: return; - case ArrayWithInt32: - sortNumericVector(exec, compareFunction, callType, callData); - break; - - case ArrayWithDouble: - sortNumericVector(exec, compareFunction, callType, callData); - break; - case ArrayWithContiguous: sortNumericVector(exec, compareFunction, callType, callData); return; @@ -1062,7 +854,7 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal } template -void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevantLength) +void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier* begin, unsigned relevantLength) { if (!relevantLength) return; @@ -1083,31 +875,11 @@ void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevan Heap::heap(this)->pushTempSortVector(&values); bool isSortingPrimitiveValues = true; - switch (indexingType) { - case ArrayWithInt32: - for (size_t i = 0; i < relevantLength; i++) { - JSValue value = static_cast*>(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(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*>(begin)[i].get(); - ASSERT(!value.isUndefined()); - values[i].first = value; - isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive(); - } - break; + for (size_t i = 0; i < relevantLength; i++) { + JSValue value = begin[i].get(); + ASSERT(!value.isUndefined()); + values[i].first = value; + isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive(); } // FIXME: The following loop continues to call toString on subsequent values even after @@ -1138,10 +910,8 @@ void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevan // 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: - ensureLength(globalData, relevantLength); + ensureContiguousLength(globalData, relevantLength); break; case ArrayWithArrayStorage: @@ -1157,12 +927,8 @@ void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevan CRASH(); } - for (size_t i = 0; i < relevantLength; i++) { - if (indexingType == ArrayWithDouble) - static_cast(begin)[i] = values[i].first.asNumber(); - else - static_cast*>(begin)[i].set(globalData, this, values[i].first); - } + for (size_t i = 0; i < relevantLength; i++) + begin[i].set(globalData, this, values[i].first); Heap::heap(this)->popTempSortVector(&values); } @@ -1173,31 +939,8 @@ void JSArray::sort(ExecState* exec) switch (structure()->indexingType()) { case ArrayClass: - case ArrayWithUndecided: return; - case ArrayWithInt32: { - unsigned lengthNotIncludingUndefined; - unsigned newRelevantLength; - compactForSorting( - lengthNotIncludingUndefined, newRelevantLength); - - sortCompactedVector( - exec, m_butterfly->contiguousInt32(), lengthNotIncludingUndefined); - return; - } - - case ArrayWithDouble: { - unsigned lengthNotIncludingUndefined; - unsigned newRelevantLength; - compactForSorting( - lengthNotIncludingUndefined, newRelevantLength); - - sortCompactedVector( - exec, m_butterfly->contiguousDouble(), lengthNotIncludingUndefined); - return; - } - case ArrayWithContiguous: { unsigned lengthNotIncludingUndefined; unsigned newRelevantLength; @@ -1344,12 +1087,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 = getHolyIndexQuickly(numDefined); + JSValue v = currentIndexingData()[numDefined].get(); if (!v || v.isUndefined()) break; tree.abstractor().m_nodes[numDefined].value = v; @@ -1358,7 +1101,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 = getHolyIndexQuickly(i); + JSValue v = currentIndexingData()[i].get(); if (v) { if (v.isUndefined()) ++numUndefined; @@ -1369,7 +1112,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. @@ -1384,31 +1127,16 @@ 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) { - 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); + currentIndexingData()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); ++iter; } // Put undefined values back in. - switch (structure()->indexingType()) { - case ArrayWithInt32: - case ArrayWithDouble: - ASSERT(elementsToExtractThreshold == undefinedElementsThreshold); - break; - - default: - for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i) - currentIndexingData()[i].setUndefined(); - } + 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) { - if (structure()->indexingType() == ArrayWithDouble) - butterfly()->contiguousDouble()[i] = QNaN; - else - currentIndexingData()[i].clear(); - } + for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) + currentIndexingData()[i].clear(); if (hasArrayStorage(structure()->indexingType())) arrayStorage()->m_numValuesInVector = newUsedVectorLength; @@ -1420,17 +1148,8 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, switch (structure()->indexingType()) { case ArrayClass: - case ArrayWithUndecided: return; - case ArrayWithInt32: - sortVector(exec, compareFunction, callType, callData); - return; - - case ArrayWithDouble: - sortVector(exec, compareFunction, callType, callData); - return; - case ArrayWithContiguous: sortVector(exec, compareFunction, callType, callData); return; @@ -1454,30 +1173,11 @@ 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(); @@ -1516,31 +1216,12 @@ 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; @@ -1578,40 +1259,12 @@ 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()[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()[i].get(); if (v) { if (v.isUndefined()) @@ -1626,23 +1279,10 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt if (hasArrayStorage(indexingType)) ASSERT(!arrayStorage()->m_sparseMap); - switch (indexingType) { - case ArrayWithInt32: - case ArrayWithDouble: - ASSERT(numDefined == newRelevantLength); - break; - - default: - for (unsigned i = numDefined; i < newRelevantLength; ++i) - indexingData()[i].setUndefined(); - break; - } - for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) { - if (indexingType == ArrayWithDouble) - m_butterfly->contiguousDouble()[i] = QNaN; - else - indexingData()[i].clear(); - } + for (unsigned i = numDefined; i < newRelevantLength; ++i) + indexingData()[i].setUndefined(); + for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) + indexingData()[i].clear(); if (hasArrayStorage(indexingType)) arrayStorage()->m_numValuesInVector = newRelevantLength; diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index ea1ed9047..1d1e64173 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -22,7 +22,7 @@ #define JSArray_h #include "ArrayConventions.h" -#include "ButterflyInlines.h" +#include "ButterflyInlineMethods.h" #include "JSObject.h" namespace JSC { @@ -162,7 +162,7 @@ private: void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&); template - void sortCompactedVector(ExecState*, void* begin, unsigned relevantLength); + void sortCompactedVector(ExecState*, WriteBarrier* begin, unsigned relevantLength); template void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&); @@ -174,14 +174,13 @@ private: void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength); }; -inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length, unsigned& vectorLength) +inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length) { IndexingHeader header; - vectorLength = std::max(length, BASE_VECTOR_LEN); - header.setVectorLength(vectorLength); + header.setVectorLength(std::max(length, BASE_VECTOR_LEN)); header.setPublicLength(length); Butterfly* result = Butterfly::create( - globalData, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue)); + globalData, 0, 0, true, header, header.vectorLength() * sizeof(EncodedJSValue)); return result; } @@ -201,23 +200,13 @@ Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData&, unsigned inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength) { Butterfly* butterfly; - 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); + if (LIKELY(structure->indexingType() == ArrayWithContiguous)) { + butterfly = createContiguousArrayButterfly(globalData, initialLength); 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 - || structure->indexingType() == ArrayWithArrayStorage); + || (initialLength && structure->indexingType() == ArrayWithArrayStorage)); butterfly = createArrayButterfly(globalData, initialLength); } JSArray* array = new (NotNull, allocateCell(globalData.heap)) JSArray(globalData, structure, butterfly); @@ -232,13 +221,8 @@ inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Struct return 0; Butterfly* butterfly; - if (LIKELY(!hasArrayStorage(structure->indexingType()))) { - ASSERT( - hasUndecided(structure->indexingType()) - || hasInt32(structure->indexingType()) - || hasDouble(structure->indexingType()) - || hasContiguous(structure->indexingType())); - + if (LIKELY(structure->indexingType() == ArrayWithContiguous)) { + 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 df31b8542..3b37613d1 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 "JSValueInlines.h" +#include "JSValueInlineMethods.h" #include "SlotVisitor.h" -#include "SlotVisitorInlines.h" +#include "SlotVisitorInlineMethods.h" #include "TypedArrayDescriptor.h" #include "WriteBarrier.h" #include diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index a7c6c8c18..c466a2b04 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -230,16 +230,9 @@ void JSGlobalObject::reset(JSValue prototype) m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject::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_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_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_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()))); @@ -367,9 +360,7 @@ inline bool hasBrokenIndexing(JSObject* object) { // This will change if we have more indexing types. IndexingType type = object->structure()->indexingType(); - // 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); + return hasContiguous(type) || hasFastArrayStorage(type); } void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell) @@ -421,8 +412,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. - for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) - m_arrayStructureForIndexingShapeDuringAllocation[i].set(globalData, this, originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage)); + m_arrayStructure.set(globalData, this, m_arrayStructureForSlowPut.get()); + m_arrayStructureWithArrayStorage.set(globalData, this, m_arrayStructureForSlowPut.get()); // Make sure that all objects that have indexed storage switch to the slow kind of // indexed storage. @@ -497,10 +488,9 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_activationStructure); visitor.append(&thisObject->m_nameScopeStructure); visitor.append(&thisObject->m_argumentsStructure); - 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_arrayStructure); + visitor.append(&thisObject->m_arrayStructureWithArrayStorage); + visitor.append(&thisObject->m_arrayStructureForSlowPut); 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 121b71b72..3212363ab 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -22,7 +22,6 @@ #ifndef JSGlobalObject_h #define JSGlobalObject_h -#include "ArrayAllocationProfile.h" #include "JSArray.h" #include "JSGlobalData.h" #include "JSSegmentedVariableObject.h" @@ -131,12 +130,9 @@ namespace JSC { WriteBarrier m_activationStructure; WriteBarrier m_nameScopeStructure; WriteBarrier m_argumentsStructure; - - // Lists the actual structures used for having these particular indexing shapes. - WriteBarrier m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes]; - // Lists the structures we should use during allocation for these particular indexing shapes. - WriteBarrier m_arrayStructureForIndexingShapeDuringAllocation[NumberOfIndexingShapes]; - + WriteBarrier m_arrayStructure; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time. + WriteBarrier m_arrayStructureWithArrayStorage; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time. + WriteBarrier m_arrayStructureForSlowPut; WriteBarrier m_booleanObjectStructure; WriteBarrier m_callbackConstructorStructure; WriteBarrier m_callbackFunctionStructure; @@ -279,26 +275,14 @@ namespace JSC { Structure* activationStructure() const { return m_activationStructure.get(); } Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); } Structure* argumentsStructure() const { return m_argumentsStructure.get(); } - 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)); - } - + Structure* arrayStructure() const { return m_arrayStructure.get(); } + Structure* arrayStructureWithArrayStorage() const { return m_arrayStructureWithArrayStorage.get(); } + void* addressOfArrayStructure() { return &m_arrayStructure; } + void* addressOfArrayStructureWithArrayStorage() { return &m_arrayStructureWithArrayStorage; } bool isOriginalArrayStructure(Structure* structure) { - return originalArrayStructureForIndexingType(structure->indexingType() | IsArray) == structure; + return structure == m_arrayStructure.get() || structure == m_arrayStructureWithArrayStorage.get(); } - Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); } Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); } Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); } @@ -513,34 +497,34 @@ namespace JSC { return constructEmptyObject(exec, exec->lexicalGlobalObject()); } - inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0) + inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength = 0) { - return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength)); + return JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureWithArrayStorage() : globalObject->arrayStructure(), initialLength); } - inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0) + inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength = 0) { - return constructEmptyArray(exec, profile, exec->lexicalGlobalObject(), initialLength); + return constructEmptyArray(exec, exec->lexicalGlobalObject(), initialLength); } - inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList& values) + inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const ArgList& values) { - return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values)); + return constructArray(exec, globalObject->arrayStructure(), values); } - inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList& values) + inline JSArray* constructArray(ExecState* exec, const ArgList& values) { - return constructArray(exec, profile, exec->lexicalGlobalObject(), values); + return constructArray(exec, exec->lexicalGlobalObject(), values); } - inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length) + inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const JSValue* values, unsigned length) { - return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values, length)); + return constructArray(exec, globalObject->arrayStructure(), values, length); } - inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length) + inline JSArray* constructArray(ExecState* exec, const JSValue* values, unsigned length) { - return constructArray(exec, profile, exec->lexicalGlobalObject(), values, length); + return constructArray(exec, exec->lexicalGlobalObject(), values, length); } class DynamicGlobalObjectScope { diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index a67896b1a..6a3fb84e4 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -24,14 +24,14 @@ #include "config.h" #include "JSObject.h" -#include "ButterflyInlines.h" -#include "CopiedSpaceInlines.h" +#include "ButterflyInlineMethods.h" +#include "CopiedSpaceInlineMethods.h" #include "CopyVisitor.h" -#include "CopyVisitorInlines.h" +#include "CopyVisitorInlineMethods.h" #include "DatePrototype.h" #include "ErrorConstructor.h" #include "GetterSetter.h" -#include "IndexingHeaderInlines.h" +#include "IndexingHeaderInlineMethods.h" #include "JSFunction.h" #include "JSGlobalObject.h" #include "Lookup.h" @@ -42,7 +42,7 @@ #include "PropertyDescriptor.h" #include "PropertyNameArray.h" #include "Reject.h" -#include "SlotVisitorInlines.h" +#include "SlotVisitorInlineMethods.h" #include #include @@ -129,16 +129,7 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt size_t count; switch (structure->indexingType()) { - 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: { + case ALL_CONTIGUOUS_INDEXING_TYPES: { currentTarget = newButterfly->contiguous(); currentSource = butterfly->contiguous(); ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength()); @@ -161,7 +152,8 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt break; } - memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue)); + while (count--) + (currentTarget++)->setWithoutWriteBarrier((currentSource++)->get()); } m_butterfly = newButterfly; @@ -280,10 +272,8 @@ 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()) @@ -298,20 +288,6 @@ 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()) @@ -429,22 +405,6 @@ 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()) @@ -455,29 +415,6 @@ 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(); @@ -570,13 +507,10 @@ 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, ensureArrayStorageSlow(globalData)); + enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData)); break; case ALL_ARRAY_STORAGE_INDEXING_TYPES: enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage()); @@ -600,7 +534,7 @@ void JSObject::notifyPresenceOfIndexedAccessors(JSGlobalData& globalData) globalObject()->haveABadTime(globalData); } -Butterfly* JSObject::createInitialIndexedStorage(JSGlobalData& globalData, unsigned length, size_t elementSize) +WriteBarrier* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length) { ASSERT(length < MAX_ARRAY_INDEX); IndexingType oldType = structure()->indexingType(); @@ -610,41 +544,9 @@ Butterfly* JSObject::createInitialIndexedStorage(JSGlobalData& globalData, unsig unsigned vectorLength = std::max(length, BASE_VECTOR_LEN); Butterfly* newButterfly = m_butterfly->growArrayRight( globalData, structure(), structure()->outOfLineCapacity(), false, 0, - elementSize * vectorLength); + sizeof(EncodedJSValue) * 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* 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* 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(); @@ -675,33 +577,10 @@ ArrayStorage* JSObject::createInitialArrayStorage(JSGlobalData& globalData) return createArrayStorage(globalData, 0, BASE_VECTOR_LEN); } -WriteBarrier* JSObject::convertUndecidedToInt32(JSGlobalData& globalData) -{ - ASSERT(hasUndecided(structure()->indexingType())); - setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateInt32)); - return m_butterfly->contiguousInt32(); -} - -double* JSObject::convertUndecidedToDouble(JSGlobalData& globalData) +ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) { - ASSERT(hasUndecided(structure()->indexingType())); - - for (unsigned i = m_butterfly->vectorLength(); i--;) - m_butterfly->contiguousDouble()[i] = QNaN; + ASSERT(hasContiguous(structure()->indexingType())); - setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateDouble)); - return m_butterfly->contiguousDouble(); -} - -WriteBarrier* 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(); @@ -720,141 +599,7 @@ ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(JSG newStorage->m_sparseMap.clear(); newStorage->m_indexBias = 0; newStorage->m_numValuesInVector = 0; - - 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* current = &m_butterfly->contiguousInt32()[i]; - double* currentAsDouble = bitwise_cast(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* 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; - newStorage->m_vector[i].setWithoutWriteBarrier(v); - newStorage->m_numValuesInVector++; - } - - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); - 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* JSObject::convertDoubleToContiguous(JSGlobalData& globalData) -{ - ASSERT(hasDouble(structure()->indexingType())); - - for (unsigned i = m_butterfly->vectorLength(); i--;) { - double* current = &m_butterfly->contiguousDouble()[i]; - WriteBarrier* currentAsValue = bitwise_cast*>(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--;) { + for (unsigned i = publicLength; i--;) { JSValue v = m_butterfly->contiguous()[i].get(); if (!v) continue; @@ -863,7 +608,7 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData } Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); - setButterfly(globalData, newStorage->butterfly(), newStructure); + setButterfly(globalData, newButterfly, newStructure); return newStorage; } @@ -877,154 +622,48 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData return convertContiguousToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); } -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* JSObject::ensureInt32Slow(JSGlobalData& globalData) +WriteBarrier* JSObject::ensureContiguousSlow(JSGlobalData& globalData) { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) return 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; + return createInitialContiguous(globalData, 0); default: - CRASH(); + ASSERT_NOT_REACHED(); return 0; } } -double* JSObject::ensureDoubleSlow(JSGlobalData& globalData) +ArrayStorage* JSObject::ensureArrayStorageSlow(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: - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return 0; + ASSERT(!indexingShouldBeSparse()); + ASSERT(!structure()->needsSlowPutIndexing()); + return convertContiguousToArrayStorage(globalData); - default: - CRASH(); - return 0; - } -} - -WriteBarrier* JSObject::ensureContiguousSlow(JSGlobalData& globalData) -{ - switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: - 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; + if (UNLIKELY(indexingShouldBeSparse())) + return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData); + return createInitialArrayStorage(globalData); default: - CRASH(); + ASSERT_NOT_REACHED(); return 0; } } -ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData) +Butterfly* JSObject::ensureIndexedStorageSlow(JSGlobalData& globalData) { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: + if (UNLIKELY(structure()->needsSlowPutIndexing())) + return createInitialArrayStorage(globalData)->butterfly(); if (UNLIKELY(indexingShouldBeSparse())) - 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); + return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)->butterfly(); + return Butterfly::fromContiguous(createInitialContiguous(globalData, 0)); default: ASSERT_NOT_REACHED(); @@ -1035,6 +674,13 @@ ArrayStorage* JSObject::ensureArrayStorageSlow(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); @@ -1042,23 +688,8 @@ 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: - CRASH(); + ASSERT_NOT_REACHED(); return 0; } } @@ -1066,21 +697,10 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData) { switch (structure()->indexingType()) { - 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: + case ALL_CONTIGUOUS_INDEXING_TYPES: { convertContiguousToArrayStorage(globalData, AllocateSlowPutArrayStorage); break; + } case NonArrayWithArrayStorage: case ArrayWithArrayStorage: { @@ -1090,7 +710,7 @@ void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData) } default: - CRASH(); + ASSERT_NOT_REACHED(); break; } } @@ -1257,10 +877,8 @@ 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()) @@ -1269,14 +887,6 @@ 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(); @@ -1448,10 +1058,8 @@ 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(); @@ -1463,18 +1071,6 @@ 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(); @@ -1864,10 +1460,9 @@ bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, J return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow); } -template -void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, unsigned i, JSValue value) +void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState* exec, unsigned i, JSValue value) { - ASSERT((structure()->indexingType() & IndexingShapeMask) == indexingShape); + ASSERT(hasContiguous(structure()->indexingType())); ASSERT(!indexingShouldBeSparse()); // For us to get here, the index is either greater than the public length, or greater than @@ -1878,9 +1473,9 @@ void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, un if (i >= MAX_ARRAY_INDEX - 1 || (i >= MIN_SPARSE_ARRAY_INDEX - && !isDenseEnoughForVector(i, countElements(m_butterfly)))) { + && !isDenseEnoughForVector(i, countElementsInContiguous(m_butterfly)))) { ASSERT(i <= MAX_ARRAY_INDEX); - ensureArrayStorageSlow(globalData); + convertContiguousToArrayStorage(globalData, AllocateArrayStorage); SparseArrayValueMap* map = allocateSparseIndexMap(globalData); map->putEntry(exec, this, i, value, false); ASSERT(i >= arrayStorage()->length()); @@ -1888,30 +1483,10 @@ void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, un return; } - ensureLength(globalData, i + 1); + ensureContiguousLength(globalData, i + 1); ASSERT(i < m_butterfly->vectorLength()); - 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(); - } + m_butterfly->contiguous()[i].set(globalData, this, value); } void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage) @@ -2017,23 +1592,8 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue break; } - case ALL_UNDECIDED_INDEXING_TYPES: { - CRASH(); - break; - } - - case ALL_INT32_INDEXING_TYPES: { - putByIndexBeyondVectorLengthWithoutAttributes(exec, i, value); - break; - } - - case ALL_DOUBLE_INDEXING_TYPES: { - putByIndexBeyondVectorLengthWithoutAttributes(exec, i, value); - break; - } - case ALL_CONTIGUOUS_INDEXING_TYPES: { - putByIndexBeyondVectorLengthWithoutAttributes(exec, i, value); + putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value); break; } @@ -2164,49 +1724,12 @@ 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(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(exec, i, value); - return true; - } - case ALL_CONTIGUOUS_INDEXING_TYPES: { if (attributes & (ReadOnly | Accessor)) { return putDirectIndexBeyondVectorLengthWithArrayStorage( exec, i, value, attributes, mode, convertContiguousToArrayStorage(globalData)); } - putByIndexBeyondVectorLengthWithoutAttributes(exec, i, value); + putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value); return true; } @@ -2246,65 +1769,33 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength) unsigned vectorLength; unsigned length; - if (hasIndexedProperties(structure()->indexingType())) { - vectorLength = m_butterfly->vectorLength(); - length = m_butterfly->publicLength(); - } else { + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: vectorLength = 0; length = 0; + break; + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + vectorLength = m_butterfly->vectorLength(); + length = m_butterfly->publicLength(); + break; + default: + CRASH(); + return 0; } - return getNewVectorLength(vectorLength, length, desiredLength); } -template -unsigned JSObject::countElements(Butterfly* butterfly) +unsigned JSObject::countElementsInContiguous(Butterfly* butterfly) { unsigned numValues = 0; for (unsigned i = butterfly->publicLength(); i--;) { - 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(); - } + if (butterfly->contiguous()[i]) + numValues++; } 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(m_butterfly); - - case ALL_DOUBLE_INDEXING_TYPES: - return countElements(m_butterfly); - - case ALL_CONTIGUOUS_INDEXING_TYPES: - return countElements(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 @@ -2348,24 +1839,19 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength return true; } -void JSObject::ensureLengthSlow(JSGlobalData& globalData, unsigned length) +void JSObject::ensureContiguousLengthSlow(JSGlobalData& globalData, unsigned length) { ASSERT(length < MAX_ARRAY_INDEX); - ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType())); + ASSERT(hasContiguous(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, - oldVectorLength * sizeof(EncodedJSValue), + m_butterfly->vectorLength() * 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); } @@ -2395,10 +1881,8 @@ 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()) @@ -2410,17 +1894,6 @@ 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 f9ae73ed4..82455390f 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -151,16 +151,30 @@ public: unsigned getArrayLength() const { - if (!hasIndexedProperties(structure()->indexingType())) + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: return 0; - return m_butterfly->publicLength(); + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->publicLength(); + default: + ASSERT_NOT_REACHED(); + return 0; + } } unsigned getVectorLength() { - if (!hasIndexedProperties(structure()->indexingType())) + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: return 0; - return m_butterfly->vectorLength(); + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->vectorLength(); + default: + ASSERT_NOT_REACHED(); + return 0; + } } JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); @@ -200,19 +214,9 @@ 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: @@ -224,11 +228,8 @@ 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: @@ -242,19 +243,10 @@ 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(); @@ -287,10 +279,7 @@ 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: @@ -309,10 +298,7 @@ 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(); @@ -325,14 +311,6 @@ 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); @@ -340,22 +318,6 @@ 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& x = storage->m_vector[i]; @@ -376,40 +338,12 @@ 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()); @@ -426,9 +360,6 @@ 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: @@ -443,9 +374,6 @@ 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: @@ -643,30 +571,6 @@ 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* 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* ensureContiguous(JSGlobalData& globalData) @@ -689,6 +593,14 @@ 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() @@ -749,47 +661,19 @@ protected: return 0; } } - - Butterfly* createInitialUndecided(JSGlobalData&, unsigned length); - WriteBarrier* createInitialInt32(JSGlobalData&, unsigned length); - double* createInitialDouble(JSGlobalData&, unsigned length); - WriteBarrier* createInitialContiguous(JSGlobalData&, unsigned length); - - void convertUndecidedForValue(JSGlobalData&, JSValue); - void convertInt32ForValue(JSGlobalData&, JSValue); - + ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength); ArrayStorage* createInitialArrayStorage(JSGlobalData&); - - WriteBarrier* convertUndecidedToInt32(JSGlobalData&); - double* convertUndecidedToDouble(JSGlobalData&); - WriteBarrier* convertUndecidedToContiguous(JSGlobalData&); - ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); - ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition); - ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&); - - double* convertInt32ToDouble(JSGlobalData&); - WriteBarrier* convertInt32ToContiguous(JSGlobalData&); - ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); - ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition); - ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&); - - WriteBarrier* convertDoubleToContiguous(JSGlobalData&); - ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); - ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition); - ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&); - + WriteBarrier* createInitialContiguous(JSGlobalData&, unsigned length); ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition); ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&); - ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&); bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException); - template - void putByIndexBeyondVectorLengthWithoutAttributes(ExecState*, unsigned propertyName, JSValue); + void putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState*, unsigned propertyName, JSValue); void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*); bool increaseVectorLength(JSGlobalData&, unsigned newLength); @@ -803,33 +687,24 @@ protected: // Call this if you want setIndexQuickly to succeed and you're sure that // the array is contiguous. - void ensureLength(JSGlobalData& globalData, unsigned length) + void ensureContiguousLength(JSGlobalData& globalData, unsigned length) { ASSERT(length < MAX_ARRAY_INDEX); - ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType())); + ASSERT(hasContiguous(structure()->indexingType())); if (m_butterfly->vectorLength() < length) - ensureLengthSlow(globalData, length); + ensureContiguousLengthSlow(globalData, length); if (m_butterfly->publicLength() < length) m_butterfly->setPublicLength(length); } - template - unsigned countElements(Butterfly*); + unsigned countElementsInContiguous(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 WriteBarrier* indexingData() { switch (indexingType) { - case ALL_INT32_INDEXING_TYPES: - case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return m_butterfly->contiguous(); @@ -845,7 +720,6 @@ protected: WriteBarrier* currentIndexingData() { switch (structure()->indexingType()) { - case ALL_INT32_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return m_butterfly->contiguous(); @@ -858,32 +732,10 @@ 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 unsigned relevantLength() { switch (indexingType) { - case ALL_INT32_INDEXING_TYPES: - case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: return m_butterfly->publicLength(); @@ -901,8 +753,6 @@ 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(); @@ -928,8 +778,6 @@ private: void isObject(); void isString(); - Butterfly* createInitialIndexedStorage(JSGlobalData&, unsigned length, size_t elementSize); - ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*); template @@ -952,18 +800,11 @@ private: JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&); - 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); + void ensureContiguousLengthSlow(JSGlobalData&, unsigned length); - WriteBarrier* ensureInt32Slow(JSGlobalData&); - double* ensureDoubleSlow(JSGlobalData&); WriteBarrier* 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 8f245f98d..e7f8cad17 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 (%p: %s, %s)", - asCell(), isObject() ? asObject(*this)->butterfly() : 0, asCell()->structure(), asCell()->structure()->classInfo()->className, + description, size, "Cell: %p (%p: %s, %s)", + asCell(), 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/JSValueInlineMethods.h new file mode 100644 index 000000000..224982e9e --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSValueInlineMethods.h @@ -0,0 +1,496 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSValueInlineMethods_h +#define JSValueInlineMethods_h + +#include "JSValue.h" + +namespace JSC { + + ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const + { + if (isInt32()) + return asInt32(); + return JSC::toInt32(toNumber(exec)); + } + + inline uint32_t JSValue::toUInt32(ExecState* exec) const + { + // See comment on JSC::toUInt32, above. + return toInt32(exec); + } + + inline bool JSValue::isUInt32() const + { + return isInt32() && asInt32() >= 0; + } + + inline uint32_t JSValue::asUInt32() const + { + ASSERT(isUInt32()); + return asInt32(); + } + + inline double JSValue::asNumber() const + { + ASSERT(isNumber()); + return isInt32() ? asInt32() : asDouble(); + } + + inline JSValue jsNaN() + { + return JSValue(QNaN); + } + + inline JSValue::JSValue(char i) + { + *this = JSValue(static_cast(i)); + } + + inline JSValue::JSValue(unsigned char i) + { + *this = JSValue(static_cast(i)); + } + + inline JSValue::JSValue(short i) + { + *this = JSValue(static_cast(i)); + } + + inline JSValue::JSValue(unsigned short i) + { + *this = JSValue(static_cast(i)); + } + + inline JSValue::JSValue(unsigned i) + { + if (static_cast(i) < 0) { + *this = JSValue(EncodeAsDouble, static_cast(i)); + return; + } + *this = JSValue(static_cast(i)); + } + + inline JSValue::JSValue(long i) + { + if (static_cast(i) != i) { + *this = JSValue(EncodeAsDouble, static_cast(i)); + return; + } + *this = JSValue(static_cast(i)); + } + + inline JSValue::JSValue(unsigned long i) + { + if (static_cast(i) != i) { + *this = JSValue(EncodeAsDouble, static_cast(i)); + return; + } + *this = JSValue(static_cast(i)); + } + + inline JSValue::JSValue(long long i) + { + if (static_cast(i) != i) { + *this = JSValue(EncodeAsDouble, static_cast(i)); + return; + } + *this = JSValue(static_cast(i)); + } + + inline JSValue::JSValue(unsigned long long i) + { + if (static_cast(i) != i) { + *this = JSValue(EncodeAsDouble, static_cast(i)); + return; + } + *this = JSValue(static_cast(i)); + } + + inline JSValue::JSValue(double d) + { + const int32_t asInt32 = static_cast(d); + if (asInt32 != d || (!asInt32 && signbit(d))) { // true for -0.0 + *this = JSValue(EncodeAsDouble, d); + return; + } + *this = JSValue(static_cast(d)); + } + + inline EncodedJSValue JSValue::encode(JSValue value) + { + return value.u.asInt64; + } + + inline JSValue JSValue::decode(EncodedJSValue encodedJSValue) + { + JSValue v; + v.u.asInt64 = encodedJSValue; + return v; + } + +#if USE(JSVALUE32_64) + inline JSValue::JSValue() + { + u.asBits.tag = EmptyValueTag; + u.asBits.payload = 0; + } + + inline JSValue::JSValue(JSNullTag) + { + u.asBits.tag = NullTag; + u.asBits.payload = 0; + } + + inline JSValue::JSValue(JSUndefinedTag) + { + u.asBits.tag = UndefinedTag; + u.asBits.payload = 0; + } + + inline JSValue::JSValue(JSTrueTag) + { + u.asBits.tag = BooleanTag; + u.asBits.payload = 1; + } + + inline JSValue::JSValue(JSFalseTag) + { + u.asBits.tag = BooleanTag; + u.asBits.payload = 0; + } + + inline JSValue::JSValue(HashTableDeletedValueTag) + { + u.asBits.tag = DeletedValueTag; + u.asBits.payload = 0; + } + + inline JSValue::JSValue(JSCell* ptr) + { + if (ptr) + u.asBits.tag = CellTag; + else + u.asBits.tag = EmptyValueTag; + u.asBits.payload = reinterpret_cast(ptr); + } + + inline JSValue::JSValue(const JSCell* ptr) + { + if (ptr) + u.asBits.tag = CellTag; + else + u.asBits.tag = EmptyValueTag; + u.asBits.payload = reinterpret_cast(const_cast(ptr)); + } + + inline JSValue::operator bool() const + { + ASSERT(tag() != DeletedValueTag); + return tag() != EmptyValueTag; + } + + inline bool JSValue::operator==(const JSValue& other) const + { + return u.asInt64 == other.u.asInt64; + } + + inline bool JSValue::operator!=(const JSValue& other) const + { + return u.asInt64 != other.u.asInt64; + } + + inline bool JSValue::isEmpty() const + { + return tag() == EmptyValueTag; + } + + inline bool JSValue::isUndefined() const + { + return tag() == UndefinedTag; + } + + inline bool JSValue::isNull() const + { + return tag() == NullTag; + } + + inline bool JSValue::isUndefinedOrNull() const + { + return isUndefined() || isNull(); + } + + inline bool JSValue::isCell() const + { + return tag() == CellTag; + } + + inline bool JSValue::isInt32() const + { + return tag() == Int32Tag; + } + + inline bool JSValue::isDouble() const + { + return tag() < LowestTag; + } + + inline bool JSValue::isTrue() const + { + return tag() == BooleanTag && payload(); + } + + inline bool JSValue::isFalse() const + { + return tag() == BooleanTag && !payload(); + } + + inline uint32_t JSValue::tag() const + { + return u.asBits.tag; + } + + inline int32_t JSValue::payload() const + { + return u.asBits.payload; + } + + inline int32_t JSValue::asInt32() const + { + ASSERT(isInt32()); + return u.asBits.payload; + } + + inline double JSValue::asDouble() const + { + ASSERT(isDouble()); + return u.asDouble; + } + + ALWAYS_INLINE JSCell* JSValue::asCell() const + { + ASSERT(isCell()); + return reinterpret_cast(u.asBits.payload); + } + + ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) + { + u.asDouble = d; + } + + inline JSValue::JSValue(int i) + { + u.asBits.tag = Int32Tag; + u.asBits.payload = i; + } + +#if ENABLE(LLINT_C_LOOP) + inline JSValue::JSValue(int32_t tag, int32_t payload) + { + u.asBits.tag = tag; + u.asBits.payload = payload; + } +#endif + + inline bool JSValue::isNumber() const + { + return isInt32() || isDouble(); + } + + inline bool JSValue::isBoolean() const + { + return isTrue() || isFalse(); + } + + inline bool JSValue::asBoolean() const + { + ASSERT(isBoolean()); + return payload(); + } + +#else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64) + + // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page. + inline JSValue::JSValue() + { + u.asInt64 = ValueEmpty; + } + + // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page. + inline JSValue::JSValue(HashTableDeletedValueTag) + { + u.asInt64 = ValueDeleted; + } + + inline JSValue::JSValue(JSCell* ptr) + { + u.asInt64 = reinterpret_cast(ptr); + } + + inline JSValue::JSValue(const JSCell* ptr) + { + u.asInt64 = reinterpret_cast(const_cast(ptr)); + } + + inline JSValue::operator bool() const + { + return u.asInt64; + } + + inline bool JSValue::operator==(const JSValue& other) const + { + return u.asInt64 == other.u.asInt64; + } + + inline bool JSValue::operator!=(const JSValue& other) const + { + return u.asInt64 != other.u.asInt64; + } + + inline bool JSValue::isEmpty() const + { + return u.asInt64 == ValueEmpty; + } + + inline bool JSValue::isUndefined() const + { + return asValue() == JSValue(JSUndefined); + } + + inline bool JSValue::isNull() const + { + return asValue() == JSValue(JSNull); + } + + inline bool JSValue::isTrue() const + { + return asValue() == JSValue(JSTrue); + } + + inline bool JSValue::isFalse() const + { + return asValue() == JSValue(JSFalse); + } + + inline bool JSValue::asBoolean() const + { + ASSERT(isBoolean()); + return asValue() == JSValue(JSTrue); + } + + inline int32_t JSValue::asInt32() const + { + ASSERT(isInt32()); + return static_cast(u.asInt64); + } + + inline bool JSValue::isDouble() const + { + return isNumber() && !isInt32(); + } + + inline JSValue::JSValue(JSNullTag) + { + u.asInt64 = ValueNull; + } + + inline JSValue::JSValue(JSUndefinedTag) + { + u.asInt64 = ValueUndefined; + } + + inline JSValue::JSValue(JSTrueTag) + { + u.asInt64 = ValueTrue; + } + + inline JSValue::JSValue(JSFalseTag) + { + u.asInt64 = ValueFalse; + } + + inline bool JSValue::isUndefinedOrNull() const + { + // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. + return (u.asInt64 & ~TagBitUndefined) == ValueNull; + } + + inline bool JSValue::isBoolean() const + { + return (u.asInt64 & ~1) == ValueFalse; + } + + inline bool JSValue::isCell() const + { + return !(u.asInt64 & TagMask); + } + + inline bool JSValue::isInt32() const + { + return (u.asInt64 & TagTypeNumber) == TagTypeNumber; + } + + inline int64_t reinterpretDoubleToInt64(double value) + { + return bitwise_cast(value); + } + inline double reinterpretInt64ToDouble(int64_t value) + { + return bitwise_cast(value); + } + + ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) + { + u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset; + } + + inline JSValue::JSValue(int i) + { + u.asInt64 = TagTypeNumber | static_cast(i); + } + + inline double JSValue::asDouble() const + { + ASSERT(isDouble()); + return reinterpretInt64ToDouble(u.asInt64 - DoubleEncodeOffset); + } + + inline bool JSValue::isNumber() const + { + return u.asInt64 & TagTypeNumber; + } + + ALWAYS_INLINE JSCell* JSValue::asCell() const + { + ASSERT(isCell()); + return u.ptr; + } + +#endif // USE(JSVALUE64) + +} // namespace JSC + +#endif // JSValueInlineMethods_h diff --git a/Source/JavaScriptCore/runtime/JSValueInlines.h b/Source/JavaScriptCore/runtime/JSValueInlines.h deleted file mode 100644 index c5a42f67f..000000000 --- a/Source/JavaScriptCore/runtime/JSValueInlines.h +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 JSValueInlines_h -#define JSValueInlines_h - -#include "JSValue.h" - -namespace JSC { - - ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const - { - if (isInt32()) - return asInt32(); - return JSC::toInt32(toNumber(exec)); - } - - inline uint32_t JSValue::toUInt32(ExecState* exec) const - { - // See comment on JSC::toUInt32, above. - return toInt32(exec); - } - - inline bool JSValue::isUInt32() const - { - return isInt32() && asInt32() >= 0; - } - - inline uint32_t JSValue::asUInt32() const - { - ASSERT(isUInt32()); - return asInt32(); - } - - inline double JSValue::asNumber() const - { - ASSERT(isNumber()); - return isInt32() ? asInt32() : asDouble(); - } - - inline JSValue jsNaN() - { - return JSValue(QNaN); - } - - inline JSValue::JSValue(char i) - { - *this = JSValue(static_cast(i)); - } - - inline JSValue::JSValue(unsigned char i) - { - *this = JSValue(static_cast(i)); - } - - inline JSValue::JSValue(short i) - { - *this = JSValue(static_cast(i)); - } - - inline JSValue::JSValue(unsigned short i) - { - *this = JSValue(static_cast(i)); - } - - inline JSValue::JSValue(unsigned i) - { - if (static_cast(i) < 0) { - *this = JSValue(EncodeAsDouble, static_cast(i)); - return; - } - *this = JSValue(static_cast(i)); - } - - inline JSValue::JSValue(long i) - { - if (static_cast(i) != i) { - *this = JSValue(EncodeAsDouble, static_cast(i)); - return; - } - *this = JSValue(static_cast(i)); - } - - inline JSValue::JSValue(unsigned long i) - { - if (static_cast(i) != i) { - *this = JSValue(EncodeAsDouble, static_cast(i)); - return; - } - *this = JSValue(static_cast(i)); - } - - inline JSValue::JSValue(long long i) - { - if (static_cast(i) != i) { - *this = JSValue(EncodeAsDouble, static_cast(i)); - return; - } - *this = JSValue(static_cast(i)); - } - - inline JSValue::JSValue(unsigned long long i) - { - if (static_cast(i) != i) { - *this = JSValue(EncodeAsDouble, static_cast(i)); - return; - } - *this = JSValue(static_cast(i)); - } - - inline JSValue::JSValue(double d) - { - const int32_t asInt32 = static_cast(d); - if (asInt32 != d || (!asInt32 && signbit(d))) { // true for -0.0 - *this = JSValue(EncodeAsDouble, d); - return; - } - *this = JSValue(static_cast(d)); - } - - inline EncodedJSValue JSValue::encode(JSValue value) - { - return value.u.asInt64; - } - - inline JSValue JSValue::decode(EncodedJSValue encodedJSValue) - { - JSValue v; - v.u.asInt64 = encodedJSValue; - return v; - } - -#if USE(JSVALUE32_64) - inline JSValue::JSValue() - { - u.asBits.tag = EmptyValueTag; - u.asBits.payload = 0; - } - - inline JSValue::JSValue(JSNullTag) - { - u.asBits.tag = NullTag; - u.asBits.payload = 0; - } - - inline JSValue::JSValue(JSUndefinedTag) - { - u.asBits.tag = UndefinedTag; - u.asBits.payload = 0; - } - - inline JSValue::JSValue(JSTrueTag) - { - u.asBits.tag = BooleanTag; - u.asBits.payload = 1; - } - - inline JSValue::JSValue(JSFalseTag) - { - u.asBits.tag = BooleanTag; - u.asBits.payload = 0; - } - - inline JSValue::JSValue(HashTableDeletedValueTag) - { - u.asBits.tag = DeletedValueTag; - u.asBits.payload = 0; - } - - inline JSValue::JSValue(JSCell* ptr) - { - if (ptr) - u.asBits.tag = CellTag; - else - u.asBits.tag = EmptyValueTag; - u.asBits.payload = reinterpret_cast(ptr); - } - - inline JSValue::JSValue(const JSCell* ptr) - { - if (ptr) - u.asBits.tag = CellTag; - else - u.asBits.tag = EmptyValueTag; - u.asBits.payload = reinterpret_cast(const_cast(ptr)); - } - - inline JSValue::operator bool() const - { - ASSERT(tag() != DeletedValueTag); - return tag() != EmptyValueTag; - } - - inline bool JSValue::operator==(const JSValue& other) const - { - return u.asInt64 == other.u.asInt64; - } - - inline bool JSValue::operator!=(const JSValue& other) const - { - return u.asInt64 != other.u.asInt64; - } - - inline bool JSValue::isEmpty() const - { - return tag() == EmptyValueTag; - } - - inline bool JSValue::isUndefined() const - { - return tag() == UndefinedTag; - } - - inline bool JSValue::isNull() const - { - return tag() == NullTag; - } - - inline bool JSValue::isUndefinedOrNull() const - { - return isUndefined() || isNull(); - } - - inline bool JSValue::isCell() const - { - return tag() == CellTag; - } - - inline bool JSValue::isInt32() const - { - return tag() == Int32Tag; - } - - inline bool JSValue::isDouble() const - { - return tag() < LowestTag; - } - - inline bool JSValue::isTrue() const - { - return tag() == BooleanTag && payload(); - } - - inline bool JSValue::isFalse() const - { - return tag() == BooleanTag && !payload(); - } - - inline uint32_t JSValue::tag() const - { - return u.asBits.tag; - } - - inline int32_t JSValue::payload() const - { - return u.asBits.payload; - } - - inline int32_t JSValue::asInt32() const - { - ASSERT(isInt32()); - return u.asBits.payload; - } - - inline double JSValue::asDouble() const - { - ASSERT(isDouble()); - return u.asDouble; - } - - ALWAYS_INLINE JSCell* JSValue::asCell() const - { - ASSERT(isCell()); - return reinterpret_cast(u.asBits.payload); - } - - ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) - { - u.asDouble = d; - } - - inline JSValue::JSValue(int i) - { - u.asBits.tag = Int32Tag; - u.asBits.payload = i; - } - -#if ENABLE(LLINT_C_LOOP) - inline JSValue::JSValue(int32_t tag, int32_t payload) - { - u.asBits.tag = tag; - u.asBits.payload = payload; - } -#endif - - inline bool JSValue::isNumber() const - { - return isInt32() || isDouble(); - } - - inline bool JSValue::isBoolean() const - { - return isTrue() || isFalse(); - } - - inline bool JSValue::asBoolean() const - { - ASSERT(isBoolean()); - return payload(); - } - -#else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64) - - // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page. - inline JSValue::JSValue() - { - u.asInt64 = ValueEmpty; - } - - // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page. - inline JSValue::JSValue(HashTableDeletedValueTag) - { - u.asInt64 = ValueDeleted; - } - - inline JSValue::JSValue(JSCell* ptr) - { - u.asInt64 = reinterpret_cast(ptr); - } - - inline JSValue::JSValue(const JSCell* ptr) - { - u.asInt64 = reinterpret_cast(const_cast(ptr)); - } - - inline JSValue::operator bool() const - { - return u.asInt64; - } - - inline bool JSValue::operator==(const JSValue& other) const - { - return u.asInt64 == other.u.asInt64; - } - - inline bool JSValue::operator!=(const JSValue& other) const - { - return u.asInt64 != other.u.asInt64; - } - - inline bool JSValue::isEmpty() const - { - return u.asInt64 == ValueEmpty; - } - - inline bool JSValue::isUndefined() const - { - return asValue() == JSValue(JSUndefined); - } - - inline bool JSValue::isNull() const - { - return asValue() == JSValue(JSNull); - } - - inline bool JSValue::isTrue() const - { - return asValue() == JSValue(JSTrue); - } - - inline bool JSValue::isFalse() const - { - return asValue() == JSValue(JSFalse); - } - - inline bool JSValue::asBoolean() const - { - ASSERT(isBoolean()); - return asValue() == JSValue(JSTrue); - } - - inline int32_t JSValue::asInt32() const - { - ASSERT(isInt32()); - return static_cast(u.asInt64); - } - - inline bool JSValue::isDouble() const - { - return isNumber() && !isInt32(); - } - - inline JSValue::JSValue(JSNullTag) - { - u.asInt64 = ValueNull; - } - - inline JSValue::JSValue(JSUndefinedTag) - { - u.asInt64 = ValueUndefined; - } - - inline JSValue::JSValue(JSTrueTag) - { - u.asInt64 = ValueTrue; - } - - inline JSValue::JSValue(JSFalseTag) - { - u.asInt64 = ValueFalse; - } - - inline bool JSValue::isUndefinedOrNull() const - { - // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. - return (u.asInt64 & ~TagBitUndefined) == ValueNull; - } - - inline bool JSValue::isBoolean() const - { - return (u.asInt64 & ~1) == ValueFalse; - } - - inline bool JSValue::isCell() const - { - return !(u.asInt64 & TagMask); - } - - inline bool JSValue::isInt32() const - { - return (u.asInt64 & TagTypeNumber) == TagTypeNumber; - } - - inline int64_t reinterpretDoubleToInt64(double value) - { - return bitwise_cast(value); - } - inline double reinterpretInt64ToDouble(int64_t value) - { - return bitwise_cast(value); - } - - ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) - { - u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset; - } - - inline JSValue::JSValue(int i) - { - u.asInt64 = TagTypeNumber | static_cast(i); - } - - inline double JSValue::asDouble() const - { - ASSERT(isDouble()); - return reinterpretInt64ToDouble(u.asInt64 - DoubleEncodeOffset); - } - - inline bool JSValue::isNumber() const - { - return u.asInt64 & TagTypeNumber; - } - - ALWAYS_INLINE JSCell* JSValue::asCell() const - { - ASSERT(isCell()); - return u.ptr; - } - -#endif // USE(JSVALUE64) - -} // namespace JSC - -#endif // JSValueInlines_h - diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp index bf27327bf..cd854417b 100644 --- a/Source/JavaScriptCore/runtime/LiteralParser.cpp +++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp @@ -27,8 +27,8 @@ #include "config.h" #include "LiteralParser.h" -#include "ButterflyInlines.h" -#include "CopiedSpaceInlines.h" +#include "ButterflyInlineMethods.h" +#include "CopiedSpaceInlineMethods.h" #include "JSArray.h" #include "JSString.h" #include "Lexer.h" @@ -548,7 +548,7 @@ JSValue LiteralParser::parse(ParserState initialState) switch(state) { startParseArray: case StartParseArray: { - JSArray* array = constructEmptyArray(m_exec, 0); + JSArray* array = constructEmptyArray(m_exec); objectStack.append(array); // fallthrough } diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp index 7e74a914b..7df047d28 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -21,8 +21,8 @@ #include "config.h" #include "ObjectConstructor.h" -#include "ButterflyInlines.h" -#include "CopiedSpaceInlines.h" +#include "ButterflyInlineMethods.h" +#include "CopiedSpaceInlineMethods.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, 0); + JSArray* names = constructEmptyArray(exec); 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, 0); + JSArray* keys = constructEmptyArray(exec); 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 ed14e895f..01df7e98c 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 "JSValueInlines.h" +#include "JSValueInlineMethods.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp index 19f3b81ad..ce9c2d2db 100644 --- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp +++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "RegExpMatchesArray.h" -#include "ButterflyInlines.h" +#include "ButterflyInlineMethods.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp index 00dd1ed74..35de40912 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.cpp +++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp @@ -21,8 +21,8 @@ #include "config.h" #include "RegExpObject.h" -#include "ButterflyInlines.h" -#include "CopiedSpaceInlines.h" +#include "ButterflyInlineMethods.h" +#include "CopiedSpaceInlineMethods.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 93009d806..5aafe8bb3 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -22,9 +22,9 @@ #include "config.h" #include "StringPrototype.h" -#include "ButterflyInlines.h" +#include "ButterflyInlineMethods.h" #include "CachedCall.h" -#include "CopiedSpaceInlines.h" +#include "CopiedSpaceInlineMethods.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, static_cast(0), list)); + return JSValue::encode(constructArray(exec, 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, 0); + JSArray* result = constructEmptyArray(exec); // 4. Let lengthA be 0. unsigned resultLength = 0; @@ -1388,10 +1388,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); - String color = a0.toWTFString(exec); - color.replaceWithLiteral('"', """); - - return JSValue::encode(jsMakeNontrivialString(exec, "", s, "")); + return JSValue::encode(jsMakeNontrivialString(exec, "value(exec), "\">", s, "")); } EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec) @@ -1436,10 +1433,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec) return JSValue::encode(jsNontrivialString(exec, impl)); } - String fontSize = a0.toWTFString(exec); - fontSize.replaceWithLiteral('"', """); - - return JSValue::encode(jsMakeNontrivialString(exec, "", s, "")); + return JSValue::encode(jsMakeNontrivialString(exec, "value(exec), "\">", s, "")); } EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec) @@ -1449,10 +1443,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); - String anchor = a0.toWTFString(exec); - anchor.replaceWithLiteral('"', """); - - return JSValue::encode(jsMakeNontrivialString(exec, "", s, "")); + return JSValue::encode(jsMakeNontrivialString(exec, "value(exec), "\">", s, "")); } EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec) @@ -1462,8 +1453,7 @@ 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.toWTFString(exec); - linkText.replaceWithLiteral('"', """); + String linkText = a0.toString(exec)->value(exec); unsigned linkTextSize = linkText.length(); unsigned stringSize = s.length(); diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index e930c022a..e733c7e23 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -543,13 +543,12 @@ Structure* Structure::nonPropertyTransition(JSGlobalData& globalData, Structure* unsigned attributes = toAttributes(transitionKind); IndexingType indexingType = newIndexingType(structure->indexingTypeIncludingHistory(), transitionKind); - if (JSGlobalObject* globalObject = structure->m_globalObject.get()) { - if (globalObject->isOriginalArrayStructure(structure)) { - Structure* result = globalObject->originalArrayStructureForIndexingType(indexingType); - if (result->indexingTypeIncludingHistory() == indexingType) { - structure->notifyTransitionFromThisStructure(); - return result; - } + JSGlobalObject* globalObject = structure->globalObject(); + if (structure == globalObject->arrayStructure()) { + Structure* transition = globalObject->arrayStructureWithArrayStorage(); + if (transition->indexingTypeIncludingHistory() == indexingType) { + structure->notifyTransitionFromThisStructure(); + return transition; } } diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h index 5291ed540..3ab7b2014 100644 --- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h @@ -43,9 +43,6 @@ 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, @@ -61,23 +58,14 @@ inline unsigned toAttributes(NonPropertyTransition transition) inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition transition) { switch (transition) { - case AllocateUndecided: - ASSERT(!hasIndexedProperties(oldType)); - 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; + ASSERT(!hasIndexedProperties(oldType)); + return oldType | ContiguousShape; case AllocateArrayStorage: - ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType)); + ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType)); return (oldType & ~IndexingShapeMask) | ArrayStorageShape; case AllocateSlowPutArrayStorage: - ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType) || hasContiguous(oldType)); + ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType)); return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; case SwitchToSlowPutArrayStorage: ASSERT(hasFastArrayStorage(oldType)); -- cgit v1.2.1