summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-11-09 09:42:44 +0100
committerSimon Hausmann <simon.hausmann@digia.com>2012-11-09 09:42:44 +0100
commita59391482883479a9b28a6f1ace6d1ebd08a7ecd (patch)
treefa539db054a20a67bff2fc891c33b0f4ec632916 /Source/JavaScriptCore
parentcfd86b747d32ac22246a1aa908eaa720c63a88c1 (diff)
downloadqtwebkit-a59391482883479a9b28a6f1ace6d1ebd08a7ecd.tar.gz
Imported WebKit commit 7bcdfab9a40db7d16b4b95bb77d78b8a59c9e701 (http://svn.webkit.org/repository/webkit/trunk@134025)
New snapshot with numerious build fixes, including MSVC 2012 and ARM Thumb-2.
Diffstat (limited to 'Source/JavaScriptCore')
-rw-r--r--Source/JavaScriptCore/API/JSClassRef.cpp4
-rw-r--r--Source/JavaScriptCore/API/JSObjectRef.cpp8
-rw-r--r--Source/JavaScriptCore/CMakeLists.txt1
-rw-r--r--Source/JavaScriptCore/ChangeLog731
-rw-r--r--Source/JavaScriptCore/Configurations/Version.xcconfig2
-rw-r--r--Source/JavaScriptCore/DerivedSources.pri2
-rw-r--r--Source/JavaScriptCore/GNUmakefile.list.am18
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.pro4
-rwxr-xr-xSource/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def6
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj22
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj76
-rw-r--r--Source/JavaScriptCore/Target.pri1
-rw-r--r--Source/JavaScriptCore/assembler/AbstractMacroAssembler.h7
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h4
-rw-r--r--Source/JavaScriptCore/assembler/X86Assembler.h9
-rw-r--r--Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp40
-rw-r--r--Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h80
-rw-r--r--Source/JavaScriptCore/bytecode/ArrayProfile.cpp7
-rw-r--r--Source/JavaScriptCore/bytecode/ArrayProfile.h48
-rw-r--r--Source/JavaScriptCore/bytecode/ByValInfo.h8
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.cpp52
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.h12
-rw-r--r--Source/JavaScriptCore/bytecode/DFGExitProfile.h2
-rw-r--r--Source/JavaScriptCore/bytecode/Instruction.h5
-rw-r--r--Source/JavaScriptCore/bytecode/Opcode.h6
-rw-r--r--Source/JavaScriptCore/bytecode/SpeculatedType.h26
-rw-r--r--Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp19
-rw-r--r--Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h11
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp13
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h1
-rw-r--r--Source/JavaScriptCore/debugger/Debugger.cpp2
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp136
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.h43
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.cpp241
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.h29
-rw-r--r--Source/JavaScriptCore/dfg/DFGBasicBlock.h3
-rw-r--r--Source/JavaScriptCore/dfg/DFGBranchDirection.h88
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp39
-rw-r--r--Source/JavaScriptCore/dfg/DFGCCallHelpers.h78
-rw-r--r--Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp6
-rw-r--r--Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h4
-rw-r--r--Source/JavaScriptCore/dfg/DFGFixupPhase.cpp64
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.cpp5
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h12
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h67
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp69
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.h8
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp75
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp162
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h46
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp511
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp348
-rw-r--r--Source/JavaScriptCore/heap/BlockAllocator.cpp2
-rw-r--r--Source/JavaScriptCore/heap/BlockAllocator.h14
-rw-r--r--Source/JavaScriptCore/heap/ConservativeRoots.cpp4
-rw-r--r--Source/JavaScriptCore/heap/CopiedBlock.h2
-rw-r--r--Source/JavaScriptCore/heap/CopiedSpace.cpp2
-rw-r--r--Source/JavaScriptCore/heap/CopiedSpaceInlines.h (renamed from Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h)7
-rw-r--r--Source/JavaScriptCore/heap/CopyVisitor.cpp2
-rw-r--r--Source/JavaScriptCore/heap/CopyVisitorInlines.h (renamed from Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h)7
-rw-r--r--Source/JavaScriptCore/heap/GCThread.cpp2
-rw-r--r--Source/JavaScriptCore/heap/GCThreadSharedData.cpp4
-rw-r--r--Source/JavaScriptCore/heap/HandleStack.cpp2
-rw-r--r--Source/JavaScriptCore/heap/Heap.cpp4
-rw-r--r--Source/JavaScriptCore/heap/Heap.h1
-rw-r--r--Source/JavaScriptCore/heap/HeapRootVisitor.h2
-rw-r--r--Source/JavaScriptCore/heap/HeapStatistics.cpp12
-rw-r--r--Source/JavaScriptCore/heap/HeapStatistics.h4
-rw-r--r--Source/JavaScriptCore/heap/MarkStack.cpp8
-rw-r--r--Source/JavaScriptCore/heap/MarkStackInlines.h (renamed from Source/JavaScriptCore/heap/MarkStackInlineMethods.h)11
-rw-r--r--Source/JavaScriptCore/heap/SlotVisitor.cpp2
-rw-r--r--Source/JavaScriptCore/heap/SlotVisitor.h2
-rw-r--r--Source/JavaScriptCore/heap/SlotVisitorInlines.h (renamed from Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h)8
-rw-r--r--Source/JavaScriptCore/heap/WeakBlock.cpp14
-rw-r--r--Source/JavaScriptCore/heap/WeakBlock.h12
-rw-r--r--Source/JavaScriptCore/heap/WeakSet.cpp4
-rw-r--r--Source/JavaScriptCore/jit/HostCallReturnValue.cpp2
-rw-r--r--Source/JavaScriptCore/jit/JIT.cpp2
-rw-r--r--Source/JavaScriptCore/jit/JIT.h19
-rw-r--r--Source/JavaScriptCore/jit/JITArithmetic.cpp12
-rw-r--r--Source/JavaScriptCore/jit/JITArithmetic32_64.cpp2
-rw-r--r--Source/JavaScriptCore/jit/JITCall.cpp2
-rw-r--r--Source/JavaScriptCore/jit/JITCall32_64.cpp2
-rw-r--r--Source/JavaScriptCore/jit/JITExceptions.cpp2
-rw-r--r--Source/JavaScriptCore/jit/JITInlines.h (renamed from Source/JavaScriptCore/jit/JITInlineMethods.h)26
-rw-r--r--Source/JavaScriptCore/jit/JITOpcodes.cpp9
-rw-r--r--Source/JavaScriptCore/jit/JITOpcodes32_64.cpp2
-rw-r--r--Source/JavaScriptCore/jit/JITPropertyAccess.cpp91
-rw-r--r--Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp74
-rw-r--r--Source/JavaScriptCore/jit/JITStubs.cpp13
-rw-r--r--Source/JavaScriptCore/jit/JITStubs.h2
-rw-r--r--Source/JavaScriptCore/jsc.cpp6
-rw-r--r--Source/JavaScriptCore/llint/LLIntSlowPaths.cpp8
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter.asm17
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm83
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter64.asm79
-rw-r--r--Source/JavaScriptCore/offlineasm/x86.rb34
-rw-r--r--Source/JavaScriptCore/runtime/ArgList.h280
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.h446
-rw-r--r--Source/JavaScriptCore/runtime/ArrayConstructor.cpp14
-rw-r--r--Source/JavaScriptCore/runtime/ArrayConstructor.h54
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.cpp16
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.h32
-rw-r--r--Source/JavaScriptCore/runtime/Butterfly.h6
-rw-r--r--Source/JavaScriptCore/runtime/ButterflyInlines.h (renamed from Source/JavaScriptCore/runtime/ButterflyInlineMethods.h)11
-rw-r--r--Source/JavaScriptCore/runtime/CodeCache.cpp37
-rw-r--r--Source/JavaScriptCore/runtime/CodeCache.h50
-rw-r--r--Source/JavaScriptCore/runtime/Executable.cpp5
-rw-r--r--Source/JavaScriptCore/runtime/Executable.h2
-rw-r--r--Source/JavaScriptCore/runtime/FunctionPrototype.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/IndexingHeaderInlines.h (renamed from Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h)9
-rw-r--r--Source/JavaScriptCore/runtime/IndexingType.cpp55
-rw-r--r--Source/JavaScriptCore/runtime/IndexingType.h46
-rw-r--r--Source/JavaScriptCore/runtime/JSActivation.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.cpp454
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.h36
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.h4
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.cpp28
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.h56
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp661
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h229
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/JSValueInlines.h (renamed from Source/JavaScriptCore/runtime/JSValueInlineMethods.h)7
-rw-r--r--Source/JavaScriptCore/runtime/LiteralParser.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/ObjectConstructor.cpp8
-rw-r--r--Source/JavaScriptCore/runtime/Operations.h2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/StringPrototype.cpp26
-rw-r--r--Source/JavaScriptCore/runtime/Structure.cpp13
-rw-r--r--Source/JavaScriptCore/runtime/StructureTransitionTable.h20
131 files changed, 5175 insertions, 1332 deletions
diff --git a/Source/JavaScriptCore/API/JSClassRef.cpp b/Source/JavaScriptCore/API/JSClassRef.cpp
index 976203f08..f30b02a2a 100644
--- a/Source/JavaScriptCore/API/JSClassRef.cpp
+++ b/Source/JavaScriptCore/API/JSClassRef.cpp
@@ -134,7 +134,7 @@ OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::JSGlobalData&, OpaqueJSC
OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end();
for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) {
ASSERT(!it->key->isIdentifier());
- staticValues->add(StringImpl::create(it->key->characters(), it->key->length()), adoptPtr(new StaticValueEntry(it->value->getProperty, it->value->setProperty, it->value->attributes)));
+ staticValues->add(it->key->isolatedCopy(), adoptPtr(new StaticValueEntry(it->value->getProperty, it->value->setProperty, it->value->attributes)));
}
}
@@ -143,7 +143,7 @@ OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::JSGlobalData&, OpaqueJSC
OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end();
for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) {
ASSERT(!it->key->isIdentifier());
- staticFunctions->add(StringImpl::create(it->key->characters(), it->key->length()), adoptPtr(new StaticFunctionEntry(it->value->callAsFunction, it->value->attributes)));
+ staticFunctions->add(it->key->isolatedCopy(), adoptPtr(new StaticFunctionEntry(it->value->callAsFunction, it->value->attributes)));
}
}
}
diff --git a/Source/JavaScriptCore/API/JSObjectRef.cpp b/Source/JavaScriptCore/API/JSObjectRef.cpp
index 491fa988f..c62efc60d 100644
--- a/Source/JavaScriptCore/API/JSObjectRef.cpp
+++ b/Source/JavaScriptCore/API/JSObjectRef.cpp
@@ -29,9 +29,9 @@
#include "JSObjectRefPrivate.h"
#include "APICast.h"
-#include "ButterflyInlineMethods.h"
+#include "ButterflyInlines.h"
#include "CodeBlock.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "DateConstructor.h"
#include "ErrorConstructor.h"
#include "FunctionConstructor.h"
@@ -144,9 +144,9 @@ JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSVa
for (size_t i = 0; i < argumentCount; ++i)
argList.append(toJS(exec, arguments[i]));
- result = constructArray(exec, argList);
+ result = constructArray(exec, static_cast<ArrayAllocationProfile*>(0), argList);
} else
- result = constructEmptyArray(exec);
+ result = constructEmptyArray(exec, 0);
if (exec->hadException()) {
if (exception)
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 393db67c3..bfaca5673 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -40,6 +40,7 @@ SET(JavaScriptCore_SOURCES
assembler/MacroAssembler.cpp
assembler/LinkBuffer.cpp
+ bytecode/ArrayAllocationProfile.cpp
bytecode/ArrayProfile.cpp
bytecode/CallLinkInfo.cpp
bytecode/CallLinkStatus.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 8479ac599..dbe22d11e 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,734 @@
+2012-11-09 Csaba Osztrogonác <ossy@webkit.org>
+
+ [Qt] Fix the LLINT build from ARMv7 platform
+ https://bugs.webkit.org/show_bug.cgi?id=101712
+
+ Reviewed by Simon Hausmann.
+
+ Enable generating of LLIntAssembly.h on ARM platforms.
+
+ * DerivedSources.pri:
+ * JavaScriptCore.pro:
+
+2012-11-08 Filip Pizlo <fpizlo@apple.com>
+
+ ArrayPrototype.h should have correct indentation
+
+ Rubber stamped by Sam Weinig.
+
+ * runtime/ArrayPrototype.h:
+
+2012-11-08 Mark Lam <mark.lam@apple.com>
+
+ Renamed ...InlineMethods.h files to ...Inlines.h.
+ https://bugs.webkit.org/show_bug.cgi?id=101145.
+
+ Reviewed by Geoffrey Garen.
+
+ This is only a refactoring effort to rename the files. There are no
+ functionality changes.
+
+ * API/JSObjectRef.cpp:
+ * GNUmakefile.list.am:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * bytecode/CodeBlock.cpp:
+ * dfg/DFGOperations.cpp:
+ * heap/ConservativeRoots.cpp:
+ * heap/CopiedBlock.h:
+ * heap/CopiedSpace.cpp:
+ * heap/CopiedSpaceInlineMethods.h: Removed.
+ * heap/CopiedSpaceInlines.h: Copied from Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h.
+ * heap/CopyVisitor.cpp:
+ * heap/CopyVisitorInlineMethods.h: Removed.
+ * heap/CopyVisitorInlines.h: Copied from Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h.
+ * heap/GCThread.cpp:
+ * heap/GCThreadSharedData.cpp:
+ * heap/HandleStack.cpp:
+ * heap/Heap.cpp:
+ * heap/HeapRootVisitor.h:
+ * heap/MarkStack.cpp:
+ * heap/MarkStackInlineMethods.h: Removed.
+ * heap/MarkStackInlines.h: Copied from Source/JavaScriptCore/heap/MarkStackInlineMethods.h.
+ * heap/SlotVisitor.cpp:
+ * heap/SlotVisitor.h:
+ * heap/SlotVisitorInlineMethods.h: Removed.
+ * heap/SlotVisitorInlines.h: Copied from Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h.
+ * jit/HostCallReturnValue.cpp:
+ * jit/JIT.cpp:
+ * jit/JITArithmetic.cpp:
+ * jit/JITArithmetic32_64.cpp:
+ * jit/JITCall.cpp:
+ * jit/JITCall32_64.cpp:
+ * jit/JITInlineMethods.h: Removed.
+ * jit/JITInlines.h: Copied from Source/JavaScriptCore/jit/JITInlineMethods.h.
+ * jit/JITOpcodes.cpp:
+ * jit/JITOpcodes32_64.cpp:
+ * jit/JITPropertyAccess.cpp:
+ * jit/JITPropertyAccess32_64.cpp:
+ * jsc.cpp:
+ * runtime/ArrayConstructor.cpp:
+ * runtime/ArrayPrototype.cpp:
+ * runtime/ButterflyInlineMethods.h: Removed.
+ * runtime/ButterflyInlines.h: Copied from Source/JavaScriptCore/runtime/ButterflyInlineMethods.h.
+ * runtime/IndexingHeaderInlineMethods.h: Removed.
+ * runtime/IndexingHeaderInlines.h: Copied from Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h.
+ * runtime/JSActivation.h:
+ * runtime/JSArray.cpp:
+ * runtime/JSArray.h:
+ * runtime/JSCell.h:
+ * runtime/JSObject.cpp:
+ * runtime/JSValueInlineMethods.h: Removed.
+ * runtime/JSValueInlines.h: Copied from Source/JavaScriptCore/runtime/JSValueInlineMethods.h.
+ * runtime/LiteralParser.cpp:
+ * runtime/ObjectConstructor.cpp:
+ * runtime/Operations.h:
+ * runtime/RegExpMatchesArray.cpp:
+ * runtime/RegExpObject.cpp:
+ * runtime/StringPrototype.cpp:
+
+2012-11-08 Filip Pizlo <fpizlo@apple.com>
+
+ ArrayConstructor.h should have correct indentation
+
+ Rubber stamped by Sam Weinig.
+
+ * runtime/ArrayConstructor.h:
+
+2012-11-08 Filip Pizlo <fpizlo@apple.com>
+
+ DFG should know that int == null is always false
+ https://bugs.webkit.org/show_bug.cgi?id=101665
+
+ Reviewed by Oliver Hunt.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+
+2012-11-08 Filip Pizlo <fpizlo@apple.com>
+
+ Arguments.h should have correct indentation
+
+ Rubber stamped by Sam Weinig.
+
+ * runtime/Arguments.h:
+
+2012-11-08 Filip Pizlo <fpizlo@apple.com>
+
+ It should be possible to JIT compile get_by_vals and put_by_vals even if the DFG is disabled.
+
+ Reviewed by Oliver Hunt.
+
+ * jit/JITInlineMethods.h:
+ (JSC::JIT::chooseArrayMode):
+
+2012-11-08 Filip Pizlo <fpizlo@apple.com>
+
+ op_call should have LLInt call link info even if the DFG is disabled
+ https://bugs.webkit.org/show_bug.cgi?id=101672
+
+ Reviewed by Oliver Hunt.
+
+ Get rid of the evil uses of fall-through.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::CodeBlock):
+
+2012-11-08 Oliver Hunt <oliver@apple.com>
+
+ Improve effectiveness of function-level caching
+ https://bugs.webkit.org/show_bug.cgi?id=101667
+
+ Reviewed by Filip Pizlo.
+
+ Added a random-eviction based cache for unlinked functions, and switch
+ UnlinkedFunctionExecutable's code references to Weak<>, thereby letting
+ us remove the explicit UnlinkedFunctionExecutable::clearCode() calls that
+ were being triggered by GC.
+
+ Refactored the random eviction part of the CodeCache into a separate data
+ structure so that I didn't have to duplicate the code again, and then used
+ that for the new function cache.
+
+ * bytecode/UnlinkedCodeBlock.cpp:
+ (JSC::UnlinkedFunctionExecutable::visitChildren):
+ (JSC::UnlinkedFunctionExecutable::codeBlockFor):
+ * bytecode/UnlinkedCodeBlock.h:
+ (JSC::UnlinkedFunctionExecutable::clearCodeForRecompilation):
+ (UnlinkedFunctionExecutable):
+ * debugger/Debugger.cpp:
+ * runtime/CodeCache.cpp:
+ (JSC::CodeCache::getCodeBlock):
+ (JSC::CodeCache::generateFunctionCodeBlock):
+ (JSC::CodeCache::getFunctionExecutableFromGlobalCode):
+ (JSC::CodeCache::usedFunctionCode):
+ (JSC):
+ * runtime/Executable.cpp:
+ (JSC::FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling):
+ (JSC::FunctionExecutable::clearCode):
+ * runtime/Executable.h:
+ (FunctionExecutable):
+
+2012-11-07 Filip Pizlo <fpizlo@apple.com>
+
+ DFG constant folding and CFG simplification should be smart enough to know that if a logical op's operand is proven to have a non-masquerading structure then it always evaluates to true
+ https://bugs.webkit.org/show_bug.cgi?id=101511
+
+ Reviewed by Oliver Hunt.
+
+ To make life easier, this moves BranchDirection into BasicBlock so that after
+ running the CFA, we always know, for each block, what direction the CFA
+ proved. CFG simplification now both uses and preserves cfaBranchDirection in
+ its transformations.
+
+ Also made both LogicalNot and Branch check whether the operand is a known cell
+ with a known structure, and if so, made them do the appropriate folding.
+
+ 5% speed-up on V8/raytrace because it makes raytrace's own null checks
+ evaporate (i.e. idioms like 'if (!x) throw "unhappiness"') thanks to the fact
+ that we were already doing structure check hoisting.
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::endBasicBlock):
+ (JSC::DFG::AbstractState::execute):
+ (JSC::DFG::AbstractState::mergeToSuccessors):
+ * dfg/DFGAbstractState.h:
+ (AbstractState):
+ * dfg/DFGBasicBlock.h:
+ (JSC::DFG::BasicBlock::BasicBlock):
+ (BasicBlock):
+ * dfg/DFGBranchDirection.h: Added.
+ (DFG):
+ (JSC::DFG::branchDirectionToString):
+ (JSC::DFG::isKnownDirection):
+ (JSC::DFG::branchCondition):
+ * dfg/DFGCFGSimplificationPhase.cpp:
+ (JSC::DFG::CFGSimplificationPhase::run):
+ (JSC::DFG::CFGSimplificationPhase::mergeBlocks):
+
+2012-11-08 Christophe Dumez <christophe.dumez@intel.com>
+
+ [JSC] HTML extensions to String.prototype should escape " as &quot; in argument values
+ https://bugs.webkit.org/show_bug.cgi?id=90667
+
+ Reviewed by Benjamin Poulain.
+
+ Escape quotation mark as &quot; in argument values to:
+ - String.prototype.anchor(name)
+ - String.prototype.fontcolor(color)
+ - String.prototype.fontsize(size)
+ - String.prototype.link(href)
+
+ This behavior matches Chromium/V8 and Firefox/Spidermonkey
+ implementations and is requited by:
+ http://mathias.html5.org/specs/javascript/#escapeattributevalue
+
+ This also fixes a potential security risk (XSS vector).
+
+ * runtime/StringPrototype.cpp:
+ (JSC::stringProtoFuncFontcolor):
+ (JSC::stringProtoFuncFontsize):
+ (JSC::stringProtoFuncAnchor):
+ (JSC::stringProtoFuncLink):
+
+2012-11-08 Anders Carlsson <andersca@apple.com>
+
+ HeapStatistics::s_pauseTimeStarts and s_pauseTimeEnds should be Vectors
+ https://bugs.webkit.org/show_bug.cgi?id=101651
+
+ Reviewed by Andreas Kling.
+
+ HeapStatistics uses Deques when Vectors would work just as good.
+
+ * heap/HeapStatistics.cpp:
+ * heap/HeapStatistics.h:
+ (HeapStatistics):
+
+2012-11-07 Filip Pizlo <fpizlo@apple.com>
+
+ DFG should not assume that something is a double just because it might be undefined
+ https://bugs.webkit.org/show_bug.cgi?id=101438
+
+ Reviewed by Oliver Hunt.
+
+ This changes all non-bitop arithmetic to (a) statically expect that variables are
+ defined prior to use in arithmetic and (b) not fall off into double paths just
+ because a value may not be a number. This is accomplished with two new notions of
+ speculation:
+
+ shouldSpeculateIntegerExpectingDefined: Should we speculate that the value is an
+ integer if we ignore undefined (i.e. SpecOther) predictions?
+
+ shouldSpeculateIntegerForArithmetic: Should we speculate that the value is an
+ integer if we ignore non-numeric predictions?
+
+ This is a ~2x speed-up on programs that seem to our prediction propagator to have
+ paths in which otherwise numeric variables are undefined.
+
+ * bytecode/SpeculatedType.h:
+ (JSC::isInt32SpeculationForArithmetic):
+ (JSC):
+ (JSC::isInt32SpeculationExpectingDefined):
+ (JSC::isDoubleSpeculationForArithmetic):
+ (JSC::isNumberSpeculationExpectingDefined):
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGGraph.h:
+ (JSC::DFG::Graph::addShouldSpeculateInteger):
+ (JSC::DFG::Graph::mulShouldSpeculateInteger):
+ (JSC::DFG::Graph::negateShouldSpeculateInteger):
+ (JSC::DFG::Graph::addImmediateShouldSpeculateInteger):
+ (JSC::DFG::Graph::mulImmediateShouldSpeculateInteger):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::shouldSpeculateIntegerForArithmetic):
+ (Node):
+ (JSC::DFG::Node::shouldSpeculateIntegerExpectingDefined):
+ (JSC::DFG::Node::shouldSpeculateDoubleForArithmetic):
+ (JSC::DFG::Node::shouldSpeculateNumberExpectingDefined):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileAdd):
+ (JSC::DFG::SpeculativeJIT::compileArithMod):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * jit/JITArithmetic.cpp:
+ (JSC::JIT::emit_op_div):
+
+2012-11-06 Filip Pizlo <fpizlo@apple.com>
+
+ JSC should infer when indexed storage contains only integers or doubles
+ https://bugs.webkit.org/show_bug.cgi?id=98606
+
+ Reviewed by Oliver Hunt.
+
+ This adds two new indexing types: int32 and double. It also adds array allocation profiling,
+ which allows array allocations to converge to allocating arrays using those types to which
+ those arrays would have been converted.
+
+ 20% speed-up on navier-stokes. 40% speed-up on various Kraken DSP tests. Some slow-downs too,
+ but a performance win overall on all benchmarks we track.
+
+ * API/JSObjectRef.cpp:
+ (JSObjectMakeArray):
+ * CMakeLists.txt:
+ * GNUmakefile.list.am:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * Target.pri:
+ * assembler/AbstractMacroAssembler.h:
+ (JumpList):
+ (JSC::AbstractMacroAssembler::JumpList::JumpList):
+ * assembler/MacroAssemblerX86Common.h:
+ (JSC::MacroAssemblerX86Common::branchDouble):
+ * assembler/X86Assembler.h:
+ (JSC::X86Assembler::jnp):
+ (X86Assembler):
+ (JSC::X86Assembler::X86InstructionFormatter::emitRex):
+ * bytecode/ArrayAllocationProfile.cpp: Added.
+ (JSC):
+ (JSC::ArrayAllocationProfile::updateIndexingType):
+ * bytecode/ArrayAllocationProfile.h: Added.
+ (JSC):
+ (ArrayAllocationProfile):
+ (JSC::ArrayAllocationProfile::ArrayAllocationProfile):
+ (JSC::ArrayAllocationProfile::selectIndexingType):
+ (JSC::ArrayAllocationProfile::updateLastAllocation):
+ (JSC::ArrayAllocationProfile::selectIndexingTypeFor):
+ (JSC::ArrayAllocationProfile::updateLastAllocationFor):
+ * bytecode/ArrayProfile.cpp:
+ (JSC::ArrayProfile::updatedObservedArrayModes):
+ (JSC):
+ * bytecode/ArrayProfile.h:
+ (JSC):
+ (JSC::arrayModesInclude):
+ (JSC::shouldUseSlowPutArrayStorage):
+ (JSC::shouldUseFastArrayStorage):
+ (JSC::shouldUseContiguous):
+ (JSC::shouldUseDouble):
+ (JSC::shouldUseInt32):
+ (ArrayProfile):
+ * bytecode/ByValInfo.h:
+ (JSC::isOptimizableIndexingType):
+ (JSC::jitArrayModeForIndexingType):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dump):
+ (JSC::CodeBlock::CodeBlock):
+ (JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
+ (JSC):
+ (JSC::CodeBlock::updateAllValueProfilePredictions):
+ (JSC::CodeBlock::updateAllArrayPredictions):
+ (JSC::CodeBlock::updateAllPredictions):
+ (JSC::CodeBlock::shouldOptimizeNow):
+ * bytecode/CodeBlock.h:
+ (CodeBlock):
+ (JSC::CodeBlock::numberOfArrayAllocationProfiles):
+ (JSC::CodeBlock::addArrayAllocationProfile):
+ (JSC::CodeBlock::updateAllValueProfilePredictions):
+ (JSC::CodeBlock::updateAllArrayPredictions):
+ * bytecode/DFGExitProfile.h:
+ (JSC::DFG::exitKindToString):
+ * bytecode/Instruction.h:
+ (JSC):
+ (JSC::Instruction::Instruction):
+ * bytecode/Opcode.h:
+ (JSC):
+ (JSC::padOpcodeName):
+ * bytecode/SpeculatedType.h:
+ (JSC):
+ (JSC::isRealNumberSpeculation):
+ * bytecode/UnlinkedCodeBlock.cpp:
+ (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
+ * bytecode/UnlinkedCodeBlock.h:
+ (JSC):
+ (JSC::UnlinkedCodeBlock::addArrayAllocationProfile):
+ (JSC::UnlinkedCodeBlock::numberOfArrayAllocationProfiles):
+ (UnlinkedCodeBlock):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::newArrayAllocationProfile):
+ (JSC):
+ (JSC::BytecodeGenerator::emitNewArray):
+ (JSC::BytecodeGenerator::emitExpectedFunctionSnippet):
+ * bytecompiler/BytecodeGenerator.h:
+ (BytecodeGenerator):
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGArrayMode.cpp:
+ (JSC::DFG::ArrayMode::fromObserved):
+ (JSC::DFG::ArrayMode::refine):
+ (DFG):
+ (JSC::DFG::ArrayMode::alreadyChecked):
+ (JSC::DFG::arrayTypeToString):
+ * dfg/DFGArrayMode.h:
+ (JSC::DFG::ArrayMode::withType):
+ (ArrayMode):
+ (JSC::DFG::ArrayMode::withTypeAndConversion):
+ (JSC::DFG::ArrayMode::usesButterfly):
+ (JSC::DFG::ArrayMode::isSpecific):
+ (JSC::DFG::ArrayMode::supportsLength):
+ (JSC::DFG::ArrayMode::arrayModesThatPassFiltering):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::getArrayMode):
+ (ByteCodeParser):
+ (JSC::DFG::ByteCodeParser::handleIntrinsic):
+ (JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCCallHelpers.h:
+ (JSC::DFG::CCallHelpers::setupArgumentsWithExecState):
+ (CCallHelpers):
+ * dfg/DFGCallArrayAllocatorSlowPathGenerator.h:
+ (JSC::DFG::CallArrayAllocatorSlowPathGenerator::generateInternal):
+ (JSC::DFG::CallArrayAllocatorWithVariableSizeSlowPathGenerator::generateInternal):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ (JSC::DFG::FixupPhase::checkArray):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::dump):
+ * dfg/DFGGraph.h:
+ (JSC::DFG::Graph::byValIsPure):
+ * dfg/DFGNode.h:
+ (NewArrayBufferData):
+ (JSC::DFG::Node::hasIndexingType):
+ (Node):
+ (JSC::DFG::Node::indexingType):
+ (JSC::DFG::Node::setIndexingType):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::emitAllocateJSArray):
+ (JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode):
+ (DFG):
+ (JSC::DFG::SpeculativeJIT::checkArray):
+ (JSC::DFG::SpeculativeJIT::arrayify):
+ (JSC::DFG::SpeculativeJIT::compileDoublePutByVal):
+ (JSC::DFG::SpeculativeJIT::compileGetArrayLength):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::callOperation):
+ (SpeculativeJIT):
+ (SpeculateIntegerOperand):
+ (JSC::DFG::SpeculateIntegerOperand::use):
+ (SpeculateDoubleOperand):
+ (JSC::DFG::SpeculateDoubleOperand::use):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (DFG):
+ (JSC::DFG::SpeculativeJIT::compileContiguousPutByVal):
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * jit/JIT.h:
+ (JSC::JIT::emitInt32GetByVal):
+ (JIT):
+ (JSC::JIT::emitInt32PutByVal):
+ (JSC::JIT::emitDoublePutByVal):
+ (JSC::JIT::emitContiguousPutByVal):
+ * jit/JITExceptions.cpp:
+ (JSC::genericThrow):
+ * jit/JITInlineMethods.h:
+ (JSC::arrayProfileSaw):
+ (JSC::JIT::chooseArrayMode):
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_new_array):
+ (JSC::JIT::emit_op_new_array_with_size):
+ (JSC::JIT::emit_op_new_array_buffer):
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emit_op_get_by_val):
+ (JSC::JIT::emitDoubleGetByVal):
+ (JSC):
+ (JSC::JIT::emitContiguousGetByVal):
+ (JSC::JIT::emit_op_put_by_val):
+ (JSC::JIT::emitGenericContiguousPutByVal):
+ (JSC::JIT::emitSlow_op_put_by_val):
+ (JSC::JIT::privateCompileGetByVal):
+ (JSC::JIT::privateCompilePutByVal):
+ * jit/JITPropertyAccess32_64.cpp:
+ (JSC::JIT::emit_op_get_by_val):
+ (JSC::JIT::emitContiguousGetByVal):
+ (JSC::JIT::emitDoubleGetByVal):
+ (JSC):
+ (JSC::JIT::emit_op_put_by_val):
+ (JSC::JIT::emitGenericContiguousPutByVal):
+ (JSC::JIT::emitSlow_op_put_by_val):
+ * jit/JITStubs.cpp:
+ (JSC::DEFINE_STUB_FUNCTION):
+ * jit/JITStubs.h:
+ (JSC):
+ * jsc.cpp:
+ (GlobalObject::finishCreation):
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::jitCompileAndSetHeuristics):
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * llint/LowLevelInterpreter.asm:
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * offlineasm/x86.rb:
+ * runtime/ArrayConstructor.cpp:
+ (JSC::constructArrayWithSizeQuirk):
+ * runtime/ArrayConstructor.h:
+ (JSC):
+ * runtime/ArrayPrototype.cpp:
+ (JSC::arrayProtoFuncConcat):
+ (JSC::arrayProtoFuncSlice):
+ (JSC::arrayProtoFuncSplice):
+ (JSC::arrayProtoFuncFilter):
+ (JSC::arrayProtoFuncMap):
+ * runtime/Butterfly.h:
+ (JSC::Butterfly::contiguousInt32):
+ (JSC::Butterfly::contiguousDouble):
+ (JSC::Butterfly::fromContiguous):
+ * runtime/ButterflyInlineMethods.h:
+ (JSC::Butterfly::createUninitializedDuringCollection):
+ * runtime/FunctionPrototype.cpp:
+ (JSC::functionProtoFuncBind):
+ * runtime/IndexingHeaderInlineMethods.h:
+ (JSC::IndexingHeader::indexingPayloadSizeInBytes):
+ * runtime/IndexingType.cpp:
+ (JSC::leastUpperBoundOfIndexingTypes):
+ (JSC):
+ (JSC::leastUpperBoundOfIndexingTypeAndType):
+ (JSC::leastUpperBoundOfIndexingTypeAndValue):
+ (JSC::indexingTypeToString):
+ * runtime/IndexingType.h:
+ (JSC):
+ (JSC::hasUndecided):
+ (JSC::hasInt32):
+ (JSC::hasDouble):
+ * runtime/JSArray.cpp:
+ (JSC::JSArray::setLength):
+ (JSC::JSArray::pop):
+ (JSC::JSArray::push):
+ (JSC::JSArray::shiftCountWithAnyIndexingType):
+ (JSC::JSArray::unshiftCountWithAnyIndexingType):
+ (JSC::compareNumbersForQSortWithInt32):
+ (JSC):
+ (JSC::compareNumbersForQSortWithDouble):
+ (JSC::JSArray::sortNumericVector):
+ (JSC::JSArray::sortNumeric):
+ (JSC::JSArray::sortCompactedVector):
+ (JSC::JSArray::sort):
+ (JSC::JSArray::sortVector):
+ (JSC::JSArray::fillArgList):
+ (JSC::JSArray::copyToArguments):
+ (JSC::JSArray::compactForSorting):
+ * runtime/JSArray.h:
+ (JSArray):
+ (JSC::createContiguousArrayButterfly):
+ (JSC::JSArray::create):
+ (JSC::JSArray::tryCreateUninitialized):
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::reset):
+ (JSC):
+ (JSC::JSGlobalObject::haveABadTime):
+ (JSC::JSGlobalObject::visitChildren):
+ * runtime/JSGlobalObject.h:
+ (JSGlobalObject):
+ (JSC::JSGlobalObject::originalArrayStructureForIndexingType):
+ (JSC::JSGlobalObject::arrayStructureForIndexingTypeDuringAllocation):
+ (JSC::JSGlobalObject::arrayStructureForProfileDuringAllocation):
+ (JSC::JSGlobalObject::isOriginalArrayStructure):
+ (JSC::constructEmptyArray):
+ (JSC::constructArray):
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::copyButterfly):
+ (JSC::JSObject::getOwnPropertySlotByIndex):
+ (JSC::JSObject::putByIndex):
+ (JSC::JSObject::enterDictionaryIndexingMode):
+ (JSC::JSObject::createInitialIndexedStorage):
+ (JSC):
+ (JSC::JSObject::createInitialUndecided):
+ (JSC::JSObject::createInitialInt32):
+ (JSC::JSObject::createInitialDouble):
+ (JSC::JSObject::createInitialContiguous):
+ (JSC::JSObject::convertUndecidedToInt32):
+ (JSC::JSObject::convertUndecidedToDouble):
+ (JSC::JSObject::convertUndecidedToContiguous):
+ (JSC::JSObject::constructConvertedArrayStorageWithoutCopyingElements):
+ (JSC::JSObject::convertUndecidedToArrayStorage):
+ (JSC::JSObject::convertInt32ToDouble):
+ (JSC::JSObject::convertInt32ToContiguous):
+ (JSC::JSObject::convertInt32ToArrayStorage):
+ (JSC::JSObject::convertDoubleToContiguous):
+ (JSC::JSObject::convertDoubleToArrayStorage):
+ (JSC::JSObject::convertContiguousToArrayStorage):
+ (JSC::JSObject::convertUndecidedForValue):
+ (JSC::JSObject::convertInt32ForValue):
+ (JSC::JSObject::setIndexQuicklyToUndecided):
+ (JSC::JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex):
+ (JSC::JSObject::convertDoubleToContiguousWhilePerformingSetIndex):
+ (JSC::JSObject::ensureInt32Slow):
+ (JSC::JSObject::ensureDoubleSlow):
+ (JSC::JSObject::ensureContiguousSlow):
+ (JSC::JSObject::ensureArrayStorageSlow):
+ (JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode):
+ (JSC::JSObject::switchToSlowPutArrayStorage):
+ (JSC::JSObject::deletePropertyByIndex):
+ (JSC::JSObject::getOwnPropertyNames):
+ (JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes):
+ (JSC::JSObject::putByIndexBeyondVectorLength):
+ (JSC::JSObject::putDirectIndexBeyondVectorLength):
+ (JSC::JSObject::getNewVectorLength):
+ (JSC::JSObject::countElements):
+ (JSC::JSObject::ensureLengthSlow):
+ (JSC::JSObject::getOwnPropertyDescriptor):
+ * runtime/JSObject.h:
+ (JSC::JSObject::getArrayLength):
+ (JSC::JSObject::getVectorLength):
+ (JSC::JSObject::canGetIndexQuickly):
+ (JSC::JSObject::getIndexQuickly):
+ (JSC::JSObject::tryGetIndexQuickly):
+ (JSC::JSObject::canSetIndexQuickly):
+ (JSC::JSObject::canSetIndexQuicklyForPutDirect):
+ (JSC::JSObject::setIndexQuickly):
+ (JSC::JSObject::initializeIndex):
+ (JSC::JSObject::hasSparseMap):
+ (JSC::JSObject::inSparseIndexingMode):
+ (JSObject):
+ (JSC::JSObject::ensureInt32):
+ (JSC::JSObject::ensureDouble):
+ (JSC::JSObject::ensureLength):
+ (JSC::JSObject::indexingData):
+ (JSC::JSObject::currentIndexingData):
+ (JSC::JSObject::getHolyIndexQuickly):
+ (JSC::JSObject::relevantLength):
+ (JSC::JSObject::currentRelevantLength):
+ * runtime/JSValue.cpp:
+ (JSC::JSValue::description):
+ * runtime/LiteralParser.cpp:
+ (JSC::::parse):
+ * runtime/ObjectConstructor.cpp:
+ (JSC::objectConstructorGetOwnPropertyNames):
+ (JSC::objectConstructorKeys):
+ * runtime/StringPrototype.cpp:
+ (JSC::stringProtoFuncMatch):
+ (JSC::stringProtoFuncSplit):
+ * runtime/Structure.cpp:
+ (JSC::Structure::nonPropertyTransition):
+ * runtime/StructureTransitionTable.h:
+ (JSC::newIndexingType):
+
+2012-11-08 Balazs Kilvady <kilvadyb@homejinni.com>
+
+ ASSERT problem on MIPS
+ https://bugs.webkit.org/show_bug.cgi?id=100589
+
+ Reviewed by Oliver Hunt.
+
+ ASSERT fix for MIPS arch.
+
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_resolve_operations):
+
+2012-11-08 Michael Saboff <msaboff@apple.com>
+
+ OpaqueJSClassContextData() should use StringImpl::isolatedCopy() to make string copies
+ https://bugs.webkit.org/show_bug.cgi?id=101507
+
+ Reviewed by Andreas Kling.
+
+ Changed to use isolatedCopy() for key Strings.
+
+ * API/JSClassRef.cpp:
+ (OpaqueJSClassContextData::OpaqueJSClassContextData):
+
+2012-11-07 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ WeakBlocks should be HeapBlocks
+ https://bugs.webkit.org/show_bug.cgi?id=101411
+
+ Reviewed by Oliver Hunt.
+
+ Currently WeakBlocks use fastMalloc memory. They are very similar to the other HeapBlocks, however,
+ so we should change them to being allocated with the BlockAllocator.
+
+ * heap/BlockAllocator.cpp:
+ (JSC::BlockAllocator::BlockAllocator):
+ * heap/BlockAllocator.h: Added a new RegionSet for WeakBlocks.
+ (JSC):
+ (BlockAllocator):
+ (JSC::WeakBlock):
+ * heap/Heap.h: Friended WeakSet to allow access to the BlockAllocator.
+ (Heap):
+ * heap/WeakBlock.cpp:
+ (JSC::WeakBlock::create): Refactored to use HeapBlocks rather than fastMalloc.
+ (JSC::WeakBlock::WeakBlock):
+ * heap/WeakBlock.h: Changed the WeakBlock size to 4 KB so that it divides evenly into the Region size.
+ (JSC):
+ (WeakBlock):
+ * heap/WeakSet.cpp:
+ (JSC::WeakSet::~WeakSet):
+ (JSC::WeakSet::addAllocator):
+
+2012-11-07 Filip Pizlo <fpizlo@apple.com>
+
+ Indentation of ArgList.h is wrong
+ https://bugs.webkit.org/show_bug.cgi?id=101441
+
+ Reviewed by Andreas Kling.
+
+ Just unindented by 4 spaces.
+
+ * runtime/ArgList.h:
+
+2012-11-07 Gabor Ballabas <gaborb@inf.u-szeged.hu>
+
+ [Qt][ARM] REGRESSION(r133688): It made all JSC and layout tests crash on ARM traditional platform
+ https://bugs.webkit.org/show_bug.cgi?id=101465
+
+ Reviewed by Oliver Hunt.
+
+ Fix failing javascriptcore tests on ARM after r133688
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::CodeBlock):
+
2012-11-06 Oliver Hunt <oliver@apple.com>
Reduce parser overhead in JSC
diff --git a/Source/JavaScriptCore/Configurations/Version.xcconfig b/Source/JavaScriptCore/Configurations/Version.xcconfig
index 3d24fe85a..f2d37774e 100644
--- a/Source/JavaScriptCore/Configurations/Version.xcconfig
+++ b/Source/JavaScriptCore/Configurations/Version.xcconfig
@@ -22,7 +22,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
MAJOR_VERSION = 537;
-MINOR_VERSION = 18;
+MINOR_VERSION = 19;
TINY_VERSION = 0;
FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION);
diff --git a/Source/JavaScriptCore/DerivedSources.pri b/Source/JavaScriptCore/DerivedSources.pri
index 03a935575..f9bbbf67c 100644
--- a/Source/JavaScriptCore/DerivedSources.pri
+++ b/Source/JavaScriptCore/DerivedSources.pri
@@ -102,7 +102,7 @@ for(dir, DIRS) {
exists($$file): LLINT_FILES += $$file
}
-if(linux-*|win32):!equals(QT_ARCH, "arm") {
+if(linux-*|win32) {
#GENERATOR: LLInt
llint.output = ${QMAKE_FILE_IN_PATH}$${QMAKE_DIR_SEP}LLIntAssembly.h
llint.script = $$PWD/offlineasm/asm.rb
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index d68a22b9f..6c7eac9e3 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -83,6 +83,8 @@ javascriptcore_sources += \
Source/JavaScriptCore/assembler/RepatchBuffer.h \
Source/JavaScriptCore/assembler/SH4Assembler.h \
Source/JavaScriptCore/assembler/X86Assembler.h \
+ Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp \
+ Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h \
Source/JavaScriptCore/bytecode/ArrayProfile.cpp \
Source/JavaScriptCore/bytecode/ArrayProfile.h \
Source/JavaScriptCore/bytecode/ByValInfo.h \
@@ -254,9 +256,9 @@ javascriptcore_sources += \
Source/JavaScriptCore/heap/CopiedBlock.h \
Source/JavaScriptCore/heap/CopiedSpace.cpp \
Source/JavaScriptCore/heap/CopiedSpace.h \
- Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h \
+ Source/JavaScriptCore/heap/CopiedSpaceInlines.h \
Source/JavaScriptCore/heap/CopyVisitor.h \
- Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h \
+ Source/JavaScriptCore/heap/CopyVisitorInlines.h \
Source/JavaScriptCore/heap/CopyVisitor.cpp \
Source/JavaScriptCore/heap/CardSet.h \
Source/JavaScriptCore/heap/ConservativeRoots.cpp \
@@ -274,7 +276,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/heap/IncrementalSweeper.cpp \
Source/JavaScriptCore/heap/SlotVisitor.cpp \
Source/JavaScriptCore/heap/SlotVisitor.h \
- Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h \
+ Source/JavaScriptCore/heap/SlotVisitorInlines.h \
Source/JavaScriptCore/heap/HandleStack.cpp \
Source/JavaScriptCore/heap/HandleStack.h \
Source/JavaScriptCore/heap/HandleTypes.h \
@@ -297,7 +299,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/heap/MachineStackMarker.h \
Source/JavaScriptCore/heap/MarkStack.cpp \
Source/JavaScriptCore/heap/MarkStack.h \
- Source/JavaScriptCore/heap/MarkStackInlineMethods.h \
+ Source/JavaScriptCore/heap/MarkStackInlines.h \
Source/JavaScriptCore/heap/HeapRootVisitor.h \
Source/JavaScriptCore/heap/MarkedAllocator.cpp \
Source/JavaScriptCore/heap/MarkedAllocator.h \
@@ -398,7 +400,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/jit/JIT.h \
Source/JavaScriptCore/jit/JITExceptions.cpp \
Source/JavaScriptCore/jit/JITExceptions.h \
- Source/JavaScriptCore/jit/JITInlineMethods.h \
+ Source/JavaScriptCore/jit/JITInlines.h \
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp \
Source/JavaScriptCore/jit/JITOpcodes.cpp \
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp \
@@ -481,7 +483,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/runtime/BooleanObject.h \
Source/JavaScriptCore/runtime/BooleanPrototype.cpp \
Source/JavaScriptCore/runtime/BooleanPrototype.h \
- Source/JavaScriptCore/runtime/ButterflyInlineMethods.h \
+ Source/JavaScriptCore/runtime/ButterflyInlines.h \
Source/JavaScriptCore/runtime/Butterfly.h \
Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h \
Source/JavaScriptCore/runtime/CallData.cpp \
@@ -529,7 +531,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/runtime/GetterSetter.h \
Source/JavaScriptCore/runtime/Identifier.cpp \
Source/JavaScriptCore/runtime/Identifier.h \
- Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h \
+ Source/JavaScriptCore/runtime/IndexingHeaderInlines.h \
Source/JavaScriptCore/runtime/IndexingHeader.h \
Source/JavaScriptCore/runtime/IndexingType.cpp \
Source/JavaScriptCore/runtime/IndexingType.h \
@@ -590,7 +592,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/runtime/JSTypeInfo.h \
Source/JavaScriptCore/runtime/JSValue.cpp \
Source/JavaScriptCore/runtime/JSValue.h \
- Source/JavaScriptCore/runtime/JSValueInlineMethods.h \
+ Source/JavaScriptCore/runtime/JSValueInlines.h \
Source/JavaScriptCore/runtime/JSVariableObject.cpp \
Source/JavaScriptCore/runtime/JSVariableObject.h \
Source/JavaScriptCore/runtime/JSWithScope.h \
diff --git a/Source/JavaScriptCore/JavaScriptCore.pro b/Source/JavaScriptCore/JavaScriptCore.pro
index c86ca8e3d..924261d4f 100644
--- a/Source/JavaScriptCore/JavaScriptCore.pro
+++ b/Source/JavaScriptCore/JavaScriptCore.pro
@@ -7,7 +7,7 @@
TEMPLATE = subdirs
CONFIG += ordered
-if(linux-*|win32*):!equals(QT_ARCH, "arm") {
+if(linux-*|win32*) {
LLIntOffsetsExtractor.file = LLIntOffsetsExtractor.pro
LLIntOffsetsExtractor.makefile = Makefile.LLIntOffsetsExtractor
SUBDIRS += LLIntOffsetsExtractor
@@ -18,7 +18,7 @@ target.file = Target.pri
SUBDIRS += derived_sources target
-if(linux-*|win32*):!equals(QT_ARCH, "arm"):addStrictSubdirOrderBetween(LLIntOffsetsExtractor, derived_sources)
+if(linux-*|win32*):addStrictSubdirOrderBetween(LLIntOffsetsExtractor, derived_sources)
addStrictSubdirOrderBetween(derived_sources, target)
jsc.file = jsc.pro
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
index b23100547..e57335015 100755
--- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
+++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
@@ -54,6 +54,7 @@ EXPORTS
?absoluteTimeToWaitTimeoutInterval@WTF@@YAKN@Z
?activityCallback@Heap@JSC@@QAEPAVGCActivityCallback@2@XZ
?add@AtomicString@WTF@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@2@PBD@Z
+ ?addFromLiteralData@AtomicString@WTF@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@2@PBDI@Z
?add@Identifier@JSC@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVJSGlobalData@2@PAVStringImpl@4@@Z
?add@Identifier@JSC@@SA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVExecState@2@PBD@Z
?add@PropertyNameArray@JSC@@QAEXPAVStringImpl@WTF@@@Z
@@ -110,11 +111,12 @@ EXPORTS
?computeHash@SHA1@WTF@@QAEXAAV?$Vector@E$0BE@@2@@Z
?configurable@PropertyDescriptor@JSC@@QBE_NXZ
?construct@JSC@@YAPAVJSObject@1@PAVExecState@1@VJSValue@1@W4ConstructType@1@ABTConstructData@1@ABVArgList@1@@Z
- ?constructArray@JSC@@YAPAVJSArray@1@PAVExecState@1@ABVArgList@1@@Z
?constructEmptyObject@JSC@@YAPAVJSObject@1@PAVExecState@1@@Z
?constructFunctionSkippingEvalEnabledCheck@JSC@@YAPAVJSObject@1@PAVExecState@1@PAVJSGlobalObject@1@ABVArgList@1@ABVIdentifier@1@ABVString@WTF@@ABVTextPosition@8@@Z
?constructNumber@JSC@@YAPAVNumberObject@1@PAVExecState@1@PAVJSGlobalObject@1@VJSValue@1@@Z
?constructString@JSC@@YAPAVStringObject@1@PAVExecState@1@PAVJSGlobalObject@1@VJSValue@1@@Z
+ ?convertDoubleToContiguousWhilePerformingSetIndex@JSObject@JSC@@AAEXAAVJSGlobalData@2@IVJSValue@2@@Z
+ ?convertInt32ToDoubleOrContiguousWhilePerformingSetIndex@JSObject@JSC@@AAEXAAVJSGlobalData@2@IVJSValue@2@@Z
?convertLatin1ToUTF8@Unicode@WTF@@YA?AW4ConversionResult@12@PAPBEPBEPAPADPAD@Z
?convertUTF16ToUTF8@Unicode@WTF@@YA?AW4ConversionResult@12@PAPB_WPB_WPAPADPAD_N@Z
?convertUTF8ToUTF16@Unicode@WTF@@YA?AW4ConversionResult@12@PAPBDPBDPAPA_WPA_WPA_N_N@Z
@@ -333,6 +335,7 @@ EXPORTS
?setGarbageCollectionTimerEnabled@Heap@JSC@@QAEX_N@Z
?setGetter@PropertyDescriptor@JSC@@QAEXVJSValue@2@@Z
?setGlobalThis@JSGlobalObject@JSC@@IAEXAAVJSGlobalData@2@PAVJSObject@2@@Z
+ ?setIndexQuicklyToUndecided@JSObject@JSC@@AAEXAAVJSGlobalData@2@IVJSValue@2@@Z
?setLoc@StatementNode@JSC@@QAEXHH@Z
?setMainThreadCallbacksPaused@WTF@@YAX_N@Z
?setOption@Options@JSC@@SA_NPBD@Z
@@ -402,6 +405,7 @@ EXPORTS
?unlock@Mutex@WTF@@QAEXXZ
?unlockAtomicallyInitializedStaticMutex@WTF@@YAXXZ
?unprotect@Heap@JSC@@QAE_NVJSValue@2@@Z
+ ?updateIndexingType@ArrayAllocationProfile@JSC@@QAEXXZ
?validate@SlotVisitor@JSC@@CAXPAVJSCell@2@@Z
?visitChildren@JSGlobalObject@JSC@@SAXPAVJSCell@2@AAVSlotVisitor@2@@Z
?visitChildren@JSObject@JSC@@SAXPAVJSCell@2@AAVSlotVisitor@2@@Z
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
index b1567e2cd..0e732d187 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
@@ -538,7 +538,7 @@
>
</File>
<File
- RelativePath="..\..\runtime\ButterflyInlineMethods.h"
+ RelativePath="..\..\runtime\ButterflyInlines.h"
>
</File>
<File
@@ -546,7 +546,7 @@
>
</File>
<File
- RelativePath="..\..\runtime\IndexingHeaderInlineMethods.h"
+ RelativePath="..\..\runtime\IndexingHeaderInlines.h"
>
</File>
<File
@@ -1010,7 +1010,7 @@
>
</File>
<File
- RelativePath="..\..\runtime\JSValueInlineMethods.h"
+ RelativePath="..\..\runtime\JSValueInlines.h"
>
</File>
<File
@@ -1582,6 +1582,14 @@
Name="bytecode"
>
<File
+ RelativePath="..\..\bytecode\ArrayAllocationProfile.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\bytecode\ArrayAllocationProfile.h"
+ >
+ </File>
+ <File
RelativePath="..\..\bytecode\ArrayProfile.cpp"
>
</File>
@@ -1978,7 +1986,7 @@
>
</File>
<File
- RelativePath="..\..\jit\JITInlineMethods.h"
+ RelativePath="..\..\jit\JITInlines.h"
>
</File>
<File
@@ -2354,7 +2362,7 @@
>
</File>
<File
- RelativePath="..\..\heap\CopiedSpaceInlineMethods.h"
+ RelativePath="..\..\heap\CopiedSpaceInlines.h"
>
</File>
<File
@@ -2366,7 +2374,7 @@
>
</File>
<File
- RelativePath="..\..\heap\CopyVisitorInlineMethods.h"
+ RelativePath="..\..\heap\CopyVisitorInlines.h"
>
</File>
<File
@@ -2554,7 +2562,7 @@
>
</File>
<File
- RelativePath="..\..\heap\MarkStackInlineMethods.h"
+ RelativePath="..\..\heap\MarkStackInlines.h"
>
</File>
<File
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 3cada1cd7..87747ca6d 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -165,6 +165,9 @@
0F7B294C14C3CD43007C3DB1 /* DFGByteCodeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5F08CC146BE602000472A9 /* DFGByteCodeCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC0977E1469EBC400CF2442 /* DFGCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8023E91613832300A0BA45 /* ByValInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */; };
+ 0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F919D0C157EE09F004A4E7D /* JSSymbolTableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */; };
0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F919D10157F3329004A4E7D /* JSSegmentedVariableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */; };
@@ -193,9 +196,9 @@
0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38915ED8E3800F167B2 /* ArrayConventions.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FB7F39615ED8E4600F167B2 /* ArrayStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FB7F39715ED8E4600F167B2 /* Butterfly.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38B15ED8E3800F167B2 /* Butterfly.h */; settings = {ATTRIBUTES = (Private, ); }; };
- 0FB7F39815ED8E4600F167B2 /* ButterflyInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38C15ED8E3800F167B2 /* ButterflyInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0FB7F39815ED8E4600F167B2 /* ButterflyInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FB7F39915ED8E4600F167B2 /* IndexingHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38D15ED8E3800F167B2 /* IndexingHeader.h */; settings = {ATTRIBUTES = (Private, ); }; };
- 0FB7F39A15ED8E4600F167B2 /* IndexingHeaderInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0FB7F39A15ED8E4600F167B2 /* IndexingHeaderInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FB7F39B15ED8E4600F167B2 /* IndexingType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38F15ED8E3800F167B2 /* IndexingType.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FB7F39D15ED8E4600F167B2 /* Reject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39115ED8E3800F167B2 /* Reject.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -450,7 +453,7 @@
863C6D9C1521111A00585E4E /* YarrCanonicalizeUCS2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 863C6D981521111200585E4E /* YarrCanonicalizeUCS2.cpp */; };
8642C510151C06A90046D4EF /* RegExpCachedResult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86F75EFB151C062F007C9BA3 /* RegExpCachedResult.cpp */; };
8642C512151C083D0046D4EF /* RegExpMatchesArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86F75EFD151C062F007C9BA3 /* RegExpMatchesArray.cpp */; };
- 865A30F1135007E100CDB49E /* JSValueInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 865A30F0135007E100CDB49E /* JSValueInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 865A30F1135007E100CDB49E /* JSValueInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 865A30F0135007E100CDB49E /* JSValueInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
865F408810E7D56300947361 /* APIShims.h in Headers */ = {isa = PBXBuildFile; fileRef = 865F408710E7D56300947361 /* APIShims.h */; settings = {ATTRIBUTES = (Private, ); }; };
866739D213BFDE710023D87C /* BigInteger.h in Headers */ = {isa = PBXBuildFile; fileRef = 866739D013BFDE710023D87C /* BigInteger.h */; };
866739D313BFDE710023D87C /* Uint16WithFraction.h in Headers */ = {isa = PBXBuildFile; fileRef = 866739D113BFDE710023D87C /* Uint16WithFraction.h */; };
@@ -486,7 +489,7 @@
86C568E211A213EE0007F7F0 /* MIPSAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C568DF11A213EE0007F7F0 /* MIPSAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
86CA032E1038E8440028A609 /* Executable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CA032D1038E8440028A609 /* Executable.cpp */; };
86CAFEE31035DDE60028A609 /* Executable.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CAFEE21035DDE60028A609 /* Executable.h */; settings = {ATTRIBUTES = (Private, ); }; };
- 86CC85A10EE79A4700288682 /* JITInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CC85A00EE79A4700288682 /* JITInlineMethods.h */; };
+ 86CC85A10EE79A4700288682 /* JITInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CC85A00EE79A4700288682 /* JITInlines.h */; };
86CC85A30EE79B7400288682 /* JITCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CC85A20EE79B7400288682 /* JITCall.cpp */; };
86CC85C40EE7A89400288682 /* JITPropertyAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CC85C30EE7A89400288682 /* JITPropertyAccess.cpp */; };
86CCEFDE0F413F8900FD7F9E /* JITCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CCEFDD0F413F8900FD7F9E /* JITCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -711,11 +714,11 @@
BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFD8C910EEB2EE700283848 /* JumpTable.h */; };
C21122E115DD9AB300790E3A /* GCThreadSharedData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */; };
C21122E215DD9AB300790E3A /* GCThreadSharedData.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C21122E315DD9AB300790E3A /* MarkStackInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C2160FE715F7E95E00942DFC /* SlotVisitorInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCB408515C0A3C30048932B /* SlotVisitorInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C21122E315DD9AB300790E3A /* MarkStackInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122E015DD9AB300790E3A /* MarkStackInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C2160FE715F7E95E00942DFC /* SlotVisitorInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2239D1716262BDD005AC5FD /* CopyVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2239D1216262BDD005AC5FD /* CopyVisitor.cpp */; };
C2239D1816262BDD005AC5FD /* CopyVisitor.h in Headers */ = {isa = PBXBuildFile; fileRef = C2239D1316262BDD005AC5FD /* CopyVisitor.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C2239D1916262BDD005AC5FD /* CopyVisitorInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = C2239D1416262BDD005AC5FD /* CopyVisitorInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C2239D1916262BDD005AC5FD /* CopyVisitorInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C2239D1416262BDD005AC5FD /* CopyVisitorInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2239D1A16262BDD005AC5FD /* GCThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2239D1516262BDD005AC5FD /* GCThread.cpp */; };
C2239D1B16262BDD005AC5FD /* GCThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C2239D1616262BDD005AC5FD /* GCThread.h */; };
C225494315F7DBAA0065E898 /* SlotVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C225494215F7DBAA0065E898 /* SlotVisitor.cpp */; };
@@ -728,7 +731,7 @@
C2A7F688160432D400F76B98 /* JSDestructibleObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C2A7F687160432D400F76B98 /* JSDestructibleObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = C2B916C114DA014E00CBAC86 /* MarkedAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2B916C514DA040C00CBAC86 /* MarkedAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2B916C414DA040C00CBAC86 /* MarkedAllocator.cpp */; };
- C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2C8D03014A3CEFC00578E65 /* CopiedBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02E14A3CEFC00578E65 /* CopiedBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2C8D03114A3CEFC00578E65 /* HeapBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2D58C3415912FEE0021A844 /* GCActivityCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */; };
@@ -951,6 +954,9 @@
0F7700911402FF280078EB39 /* SamplingCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingCounter.cpp; sourceTree = "<group>"; };
0F7B294814C3CD23007C3DB1 /* DFGCCallHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCCallHelpers.h; path = dfg/DFGCCallHelpers.h; sourceTree = "<group>"; };
0F8023E91613832300A0BA45 /* ByValInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByValInfo.h; sourceTree = "<group>"; };
+ 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBranchDirection.h; path = dfg/DFGBranchDirection.h; sourceTree = "<group>"; };
+ 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayAllocationProfile.cpp; sourceTree = "<group>"; };
+ 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayAllocationProfile.h; sourceTree = "<group>"; };
0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSymbolTableObject.cpp; sourceTree = "<group>"; };
0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSymbolTableObject.h; sourceTree = "<group>"; };
0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSegmentedVariableObject.cpp; sourceTree = "<group>"; };
@@ -979,9 +985,9 @@
0FB7F38915ED8E3800F167B2 /* ArrayConventions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayConventions.h; sourceTree = "<group>"; };
0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayStorage.h; sourceTree = "<group>"; };
0FB7F38B15ED8E3800F167B2 /* Butterfly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Butterfly.h; sourceTree = "<group>"; };
- 0FB7F38C15ED8E3800F167B2 /* ButterflyInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ButterflyInlineMethods.h; sourceTree = "<group>"; };
+ 0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ButterflyInlines.h; sourceTree = "<group>"; };
0FB7F38D15ED8E3800F167B2 /* IndexingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexingHeader.h; sourceTree = "<group>"; };
- 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexingHeaderInlineMethods.h; sourceTree = "<group>"; };
+ 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexingHeaderInlines.h; sourceTree = "<group>"; };
0FB7F38F15ED8E3800F167B2 /* IndexingType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexingType.h; sourceTree = "<group>"; };
0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyStorage.h; sourceTree = "<group>"; };
0FB7F39115ED8E3800F167B2 /* Reject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reject.h; sourceTree = "<group>"; };
@@ -1006,7 +1012,7 @@
0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WriteBarrierSupport.h; sourceTree = "<group>"; };
0FC815121405118600CFA603 /* VTableSpectrum.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VTableSpectrum.cpp; sourceTree = "<group>"; };
0FC815141405118D00CFA603 /* VTableSpectrum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTableSpectrum.h; sourceTree = "<group>"; };
- 0FCB408515C0A3C30048932B /* SlotVisitorInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlotVisitorInlineMethods.h; sourceTree = "<group>"; };
+ 0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlotVisitorInlines.h; sourceTree = "<group>"; };
0FD3C82014115CF800FD81CB /* DFGDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDriver.cpp; path = dfg/DFGDriver.cpp; sourceTree = "<group>"; };
0FD3C82214115D0E00FD81CB /* DFGDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDriver.h; path = dfg/DFGDriver.h; sourceTree = "<group>"; };
0FD81ACF154FB4EB00983E72 /* DFGDominators.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDominators.cpp; path = dfg/DFGDominators.cpp; sourceTree = "<group>"; };
@@ -1226,7 +1232,7 @@
863C6D981521111200585E4E /* YarrCanonicalizeUCS2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YarrCanonicalizeUCS2.cpp; path = yarr/YarrCanonicalizeUCS2.cpp; sourceTree = "<group>"; };
863C6D991521111200585E4E /* YarrCanonicalizeUCS2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YarrCanonicalizeUCS2.h; path = yarr/YarrCanonicalizeUCS2.h; sourceTree = "<group>"; };
863C6D9A1521111200585E4E /* YarrCanonicalizeUCS2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = YarrCanonicalizeUCS2.js; path = yarr/YarrCanonicalizeUCS2.js; sourceTree = "<group>"; };
- 865A30F0135007E100CDB49E /* JSValueInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueInlineMethods.h; sourceTree = "<group>"; };
+ 865A30F0135007E100CDB49E /* JSValueInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueInlines.h; sourceTree = "<group>"; };
865F408710E7D56300947361 /* APIShims.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIShims.h; sourceTree = "<group>"; };
866739D013BFDE710023D87C /* BigInteger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BigInteger.h; sourceTree = "<group>"; };
866739D113BFDE710023D87C /* Uint16WithFraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Uint16WithFraction.h; sourceTree = "<group>"; };
@@ -1268,7 +1274,7 @@
86C568DF11A213EE0007F7F0 /* MIPSAssembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIPSAssembler.h; sourceTree = "<group>"; };
86CA032D1038E8440028A609 /* Executable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Executable.cpp; sourceTree = "<group>"; };
86CAFEE21035DDE60028A609 /* Executable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Executable.h; sourceTree = "<group>"; };
- 86CC85A00EE79A4700288682 /* JITInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITInlineMethods.h; sourceTree = "<group>"; };
+ 86CC85A00EE79A4700288682 /* JITInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITInlines.h; sourceTree = "<group>"; };
86CC85A20EE79B7400288682 /* JITCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITCall.cpp; sourceTree = "<group>"; };
86CC85C30EE7A89400288682 /* JITPropertyAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITPropertyAccess.cpp; sourceTree = "<group>"; };
86CCEFDD0F413F8900FD7F9E /* JITCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITCode.h; sourceTree = "<group>"; };
@@ -1501,10 +1507,10 @@
BCFD8C910EEB2EE700283848 /* JumpTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JumpTable.h; sourceTree = "<group>"; };
C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCThreadSharedData.cpp; sourceTree = "<group>"; };
C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCThreadSharedData.h; sourceTree = "<group>"; };
- C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStackInlineMethods.h; sourceTree = "<group>"; };
+ C21122E015DD9AB300790E3A /* MarkStackInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStackInlines.h; sourceTree = "<group>"; };
C2239D1216262BDD005AC5FD /* CopyVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CopyVisitor.cpp; sourceTree = "<group>"; };
C2239D1316262BDD005AC5FD /* CopyVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyVisitor.h; sourceTree = "<group>"; };
- C2239D1416262BDD005AC5FD /* CopyVisitorInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyVisitorInlineMethods.h; sourceTree = "<group>"; };
+ C2239D1416262BDD005AC5FD /* CopyVisitorInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyVisitorInlines.h; sourceTree = "<group>"; };
C2239D1516262BDD005AC5FD /* GCThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCThread.cpp; sourceTree = "<group>"; };
C2239D1616262BDD005AC5FD /* GCThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCThread.h; sourceTree = "<group>"; };
C225494215F7DBAA0065E898 /* SlotVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SlotVisitor.cpp; sourceTree = "<group>"; };
@@ -1516,7 +1522,7 @@
C2A7F687160432D400F76B98 /* JSDestructibleObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDestructibleObject.h; sourceTree = "<group>"; };
C2B916C114DA014E00CBAC86 /* MarkedAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkedAllocator.h; sourceTree = "<group>"; };
C2B916C414DA040C00CBAC86 /* MarkedAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MarkedAllocator.cpp; sourceTree = "<group>"; };
- C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedSpaceInlineMethods.h; sourceTree = "<group>"; };
+ C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedSpaceInlines.h; sourceTree = "<group>"; };
C2C8D02E14A3CEFC00578E65 /* CopiedBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedBlock.h; sourceTree = "<group>"; };
C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapBlock.h; sourceTree = "<group>"; };
C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCActivityCallback.cpp; sourceTree = "<group>"; };
@@ -1816,7 +1822,7 @@
0F21C26614BE5F5E00ADC64B /* JITDriver.h */,
0F46807F14BA572700BFE272 /* JITExceptions.cpp */,
0F46808014BA572700BFE272 /* JITExceptions.h */,
- 86CC85A00EE79A4700288682 /* JITInlineMethods.h */,
+ 86CC85A00EE79A4700288682 /* JITInlines.h */,
BCDD51E90FB8DF74004A8BDC /* JITOpcodes.cpp */,
A71236E41195F33C00BD2174 /* JITOpcodes32_64.cpp */,
86CC85C30EE7A89400288682 /* JITPropertyAccess.cpp */,
@@ -1842,7 +1848,7 @@
children = (
C2239D1216262BDD005AC5FD /* CopyVisitor.cpp */,
C2239D1316262BDD005AC5FD /* CopyVisitor.h */,
- C2239D1416262BDD005AC5FD /* CopyVisitorInlineMethods.h */,
+ C2239D1416262BDD005AC5FD /* CopyVisitorInlines.h */,
C2239D1516262BDD005AC5FD /* GCThread.cpp */,
C2239D1616262BDD005AC5FD /* GCThread.h */,
C24D31E0161CD695002AA4DB /* HeapStatistics.cpp */,
@@ -1850,7 +1856,7 @@
C225494215F7DBAA0065E898 /* SlotVisitor.cpp */,
C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */,
C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */,
- C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */,
+ C21122E015DD9AB300790E3A /* MarkStackInlines.h */,
C2E526BB1590EF000054E48D /* HeapTimer.cpp */,
C2E526BC1590EF000054E48D /* HeapTimer.h */,
C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */,
@@ -1864,7 +1870,7 @@
C2C8D02E14A3CEFC00578E65 /* CopiedBlock.h */,
C240305314B404C90079EB64 /* CopiedSpace.cpp */,
C2EAA3F8149A830800FCE112 /* CopiedSpace.h */,
- C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlineMethods.h */,
+ C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlines.h */,
0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */,
0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */,
BCBE2CAD14E985AA000593AD /* GCAssertions.h */,
@@ -1896,7 +1902,7 @@
142D6F0F13539A4100B02E86 /* MarkStack.h */,
1497209014EB831500FEB1B7 /* PassWeak.h */,
14BA78F013AAB88F005B7C2C /* SlotVisitor.h */,
- 0FCB408515C0A3C30048932B /* SlotVisitorInlineMethods.h */,
+ 0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */,
142E3132134FF0A600AFADB5 /* Strong.h */,
145722851437E140005FDE26 /* StrongInlines.h */,
141448CC13A1783700F5BA1A /* TinyBloomFilter.h */,
@@ -2100,7 +2106,7 @@
BC7952340E15EB5600A898AB /* BooleanPrototype.cpp */,
BC7952350E15EB5600A898AB /* BooleanPrototype.h */,
0FB7F38B15ED8E3800F167B2 /* Butterfly.h */,
- 0FB7F38C15ED8E3800F167B2 /* ButterflyInlineMethods.h */,
+ 0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */,
869D04AE1193B54D00803475 /* CachedTranscendentalFunction.h */,
BCA62DFE0E2826230004F30D /* CallData.cpp */,
145C507F0D9DF63B0088F6B9 /* CallData.h */,
@@ -2146,7 +2152,7 @@
933A349D038AE80F008635CE /* Identifier.cpp */,
933A349A038AE7C6008635CE /* Identifier.h */,
0FB7F38D15ED8E3800F167B2 /* IndexingHeader.h */,
- 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlineMethods.h */,
+ 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlines.h */,
0F13E04C16164A1B00DC8DE7 /* IndexingType.cpp */,
0FB7F38F15ED8E3800F167B2 /* IndexingType.h */,
E178636C0D9BEEC300D74E75 /* InitializeThreading.cpp */,
@@ -2203,7 +2209,7 @@
6507D2970E871E4A00D7D896 /* JSTypeInfo.h */,
F692A8870255597D01FF60F7 /* JSValue.cpp */,
14ABB36E099C076400E2A24F /* JSValue.h */,
- 865A30F0135007E100CDB49E /* JSValueInlineMethods.h */,
+ 865A30F0135007E100CDB49E /* JSValueInlines.h */,
BC22A39A0E16E14800AF21C8 /* JSVariableObject.cpp */,
14F252560D08DD8D004ECFFF /* JSVariableObject.h */,
1442565F15EDE98D0066A49B /* JSWithScope.cpp */,
@@ -2362,6 +2368,7 @@
0FC0976B1468AB4A00CF2442 /* DFGAssemblyHelpers.cpp */,
0FC0976C1468AB4A00CF2442 /* DFGAssemblyHelpers.h */,
0F620170143FCD2F0068B77C /* DFGBasicBlock.h */,
+ 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */,
0F5F08CC146BE602000472A9 /* DFGByteCodeCache.h */,
86EC9DB41328DF82002B2AD7 /* DFGByteCodeParser.cpp */,
86EC9DB51328DF82002B2AD7 /* DFGByteCodeParser.h */,
@@ -2515,6 +2522,8 @@
969A078F0ED1D3AE00F1F681 /* bytecode */ = {
isa = PBXGroup;
children = (
+ 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */,
+ 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */,
0F63945115D07051006A597C /* ArrayProfile.cpp */,
0F63945215D07051006A597C /* ArrayProfile.h */,
0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */,
@@ -2616,14 +2625,14 @@
C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */,
FE4A332015BD2E07006F54F3 /* VMInspector.h in Headers */,
C2239D1816262BDD005AC5FD /* CopyVisitor.h in Headers */,
- C2239D1916262BDD005AC5FD /* CopyVisitorInlineMethods.h in Headers */,
+ C2239D1916262BDD005AC5FD /* CopyVisitorInlines.h in Headers */,
C24D31E3161CD695002AA4DB /* HeapStatistics.h in Headers */,
C2A7F688160432D400F76B98 /* JSDestructibleObject.h in Headers */,
FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */,
C21122E215DD9AB300790E3A /* GCThreadSharedData.h in Headers */,
- C2160FE715F7E95E00942DFC /* SlotVisitorInlineMethods.h in Headers */,
+ C2160FE715F7E95E00942DFC /* SlotVisitorInlines.h in Headers */,
C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */,
- C21122E315DD9AB300790E3A /* MarkStackInlineMethods.h in Headers */,
+ C21122E315DD9AB300790E3A /* MarkStackInlines.h in Headers */,
C25F8BCE157544A900245B71 /* IncrementalSweeper.h in Headers */,
BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */,
BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */,
@@ -2636,7 +2645,7 @@
BC18C3EC0E16F5CD00B34460 /* BooleanObject.h in Headers */,
C2C8D03014A3CEFC00578E65 /* CopiedBlock.h in Headers */,
C2EAA3FA149A835E00FCE112 /* CopiedSpace.h in Headers */,
- C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlineMethods.h in Headers */,
+ C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlines.h in Headers */,
969A07230ED1CE3300F1F681 /* BytecodeGenerator.h in Headers */,
869D04AF1193B54D00803475 /* CachedTranscendentalFunction.h in Headers */,
BC18C3ED0E16F5CD00B34460 /* CallData.h in Headers */,
@@ -2718,7 +2727,7 @@
BC18C4150E16F5CD00B34460 /* JavaScriptCorePrefix.h in Headers */,
1429D9300ED22D7000B89619 /* JIT.h in Headers */,
86CCEFDE0F413F8900FD7F9E /* JITCode.h in Headers */,
- 86CC85A10EE79A4700288682 /* JITInlineMethods.h in Headers */,
+ 86CC85A10EE79A4700288682 /* JITInlines.h in Headers */,
960626960FB8EC02009798AB /* JITStubCall.h in Headers */,
14C5242B0F5355E900BA3D04 /* JITStubs.h in Headers */,
A76F54A313B28AAB00EF2BCE /* JITWriteBarrier.h in Headers */,
@@ -2760,7 +2769,7 @@
BC18C42A0E16F5CD00B34460 /* JSType.h in Headers */,
6507D29E0E871E5E00D7D896 /* JSTypeInfo.h in Headers */,
BC18C42B0E16F5CD00B34460 /* JSValue.h in Headers */,
- 865A30F1135007E100CDB49E /* JSValueInlineMethods.h in Headers */,
+ 865A30F1135007E100CDB49E /* JSValueInlines.h in Headers */,
BC18C42C0E16F5CD00B34460 /* JSValueRef.h in Headers */,
BC18C42D0E16F5CD00B34460 /* JSVariableObject.h in Headers */,
A7482E93116A7CAD003B0712 /* JSWeakObjectMapRefInternal.h in Headers */,
@@ -2994,9 +3003,9 @@
0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */,
0FB7F39615ED8E4600F167B2 /* ArrayStorage.h in Headers */,
0FB7F39715ED8E4600F167B2 /* Butterfly.h in Headers */,
- 0FB7F39815ED8E4600F167B2 /* ButterflyInlineMethods.h in Headers */,
+ 0FB7F39815ED8E4600F167B2 /* ButterflyInlines.h in Headers */,
0FB7F39915ED8E4600F167B2 /* IndexingHeader.h in Headers */,
- 0FB7F39A15ED8E4600F167B2 /* IndexingHeaderInlineMethods.h in Headers */,
+ 0FB7F39A15ED8E4600F167B2 /* IndexingHeaderInlines.h in Headers */,
0FB7F39B15ED8E4600F167B2 /* IndexingType.h in Headers */,
0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */,
0FB7F39D15ED8E4600F167B2 /* Reject.h in Headers */,
@@ -3008,6 +3017,8 @@
0FEB3ECD16237F4D00AB67AD /* TypedArrayDescriptor.h in Headers */,
0F256C361627B0AD007F2783 /* DFGCallArrayAllocatorSlowPathGenerator.h in Headers */,
C2239D1B16262BDD005AC5FD /* GCThread.h in Headers */,
+ 0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */,
+ 0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */,
A7B601821639FD2A00372BA3 /* UnlinkedCodeBlock.h in Headers */,
A77F1822164088B200640A47 /* CodeCache.h in Headers */,
A77F1825164192C700640A47 /* ParserModes.h in Headers */,
@@ -3587,6 +3598,7 @@
C24D31E2161CD695002AA4DB /* HeapStatistics.cpp in Sources */,
C2239D1716262BDD005AC5FD /* CopyVisitor.cpp in Sources */,
C2239D1A16262BDD005AC5FD /* GCThread.cpp in Sources */,
+ 0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */,
A76F279415F13C9600517D67 /* UnlinkedCodeBlock.cpp in Sources */,
A77F1821164088B200640A47 /* CodeCache.cpp in Sources */,
);
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index b0fcc16e7..f978fb46b 100644
--- a/Source/JavaScriptCore/Target.pri
+++ b/Source/JavaScriptCore/Target.pri
@@ -50,6 +50,7 @@ SOURCES += \
assembler/MacroAssembler.cpp \
assembler/MacroAssemblerARM.cpp \
assembler/MacroAssemblerSH4.cpp \
+ bytecode/ArrayAllocationProfile.cpp \
bytecode/ArrayProfile.cpp \
bytecode/CallLinkInfo.cpp \
bytecode/CallLinkStatus.cpp \
diff --git a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
index c75adb7e9..673031b7a 100644
--- a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
+++ b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
@@ -586,6 +586,13 @@ public:
public:
typedef Vector<Jump, 16> JumpVector;
+
+ JumpList() { }
+
+ JumpList(Jump jump)
+ {
+ append(jump);
+ }
void link(AbstractMacroAssembler<AssemblerType>* masm)
{
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
index 66db26acb..53cb80c21 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
@@ -826,11 +826,15 @@ public:
m_assembler.ucomisd_rr(right, left);
if (cond == DoubleEqual) {
+ if (left == right)
+ return Jump(m_assembler.jnp());
Jump isUnordered(m_assembler.jp());
Jump result = Jump(m_assembler.je());
isUnordered.link(this);
return result;
} else if (cond == DoubleNotEqualOrUnordered) {
+ if (left == right)
+ return Jump(m_assembler.jp());
Jump isUnordered(m_assembler.jp());
Jump isEqual(m_assembler.je());
isUnordered.link(this);
diff --git a/Source/JavaScriptCore/assembler/X86Assembler.h b/Source/JavaScriptCore/assembler/X86Assembler.h
index ecb178e88..4d08b70ce 100644
--- a/Source/JavaScriptCore/assembler/X86Assembler.h
+++ b/Source/JavaScriptCore/assembler/X86Assembler.h
@@ -1475,6 +1475,12 @@ public:
return m_formatter.immediateRel32();
}
+ AssemblerLabel jnp()
+ {
+ m_formatter.twoByteOp(jccRel32(ConditionNP));
+ return m_formatter.immediateRel32();
+ }
+
AssemblerLabel jp()
{
m_formatter.twoByteOp(jccRel32(ConditionP));
@@ -2314,6 +2320,9 @@ private:
// Format a REX prefix byte.
inline void emitRex(bool w, int r, int x, int b)
{
+ ASSERT(r >= 0);
+ ASSERT(x >= 0);
+ ASSERT(b >= 0);
m_buffer.putByteUnchecked(PRE_REX | ((int)w << 3) | ((r>>3)<<2) | ((x>>3)<<1) | (b>>3));
}
diff --git a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp
new file mode 100644
index 000000000..aa682da86
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ArrayAllocationProfile.h"
+
+namespace JSC {
+
+void ArrayAllocationProfile::updateIndexingType()
+{
+ if (!m_lastArray)
+ return;
+ m_currentIndexingType = leastUpperBoundOfIndexingTypes(m_currentIndexingType, m_lastArray->structure()->indexingType());
+ m_lastArray = 0;
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h
new file mode 100644
index 000000000..a1647fad4
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ArrayAllocationProfile_h
+#define ArrayAllocationProfile_h
+
+#include "IndexingType.h"
+#include "JSArray.h"
+
+namespace JSC {
+
+class ArrayAllocationProfile {
+public:
+ ArrayAllocationProfile()
+ : m_currentIndexingType(ArrayWithUndecided)
+ , m_lastArray(0)
+ {
+ }
+
+ IndexingType selectIndexingType()
+ {
+ if (m_lastArray && UNLIKELY(m_lastArray->structure()->indexingType() != m_currentIndexingType))
+ updateIndexingType();
+ return m_currentIndexingType;
+ }
+
+ JSArray* updateLastAllocation(JSArray* lastArray)
+ {
+ m_lastArray = lastArray;
+ return lastArray;
+ }
+
+ JS_EXPORT_PRIVATE void updateIndexingType();
+
+ static IndexingType selectIndexingTypeFor(ArrayAllocationProfile* profile)
+ {
+ if (!profile)
+ return ArrayWithUndecided;
+ return profile->selectIndexingType();
+ }
+
+ static JSArray* updateLastAllocationFor(ArrayAllocationProfile* profile, JSArray* lastArray)
+ {
+ if (profile)
+ profile->updateLastAllocation(lastArray);
+ return lastArray;
+ }
+
+private:
+
+ IndexingType m_currentIndexingType;
+ JSArray* m_lastArray;
+};
+
+} // namespace JSC
+
+#endif // ArrayAllocationProfile_h
+
diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp
index 5a87380fd..51baf332f 100644
--- a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp
+++ b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp
@@ -65,6 +65,13 @@ const char* arrayModesToString(ArrayModes arrayModes)
return result;
}
+ArrayModes ArrayProfile::updatedObservedArrayModes() const
+{
+ if (m_lastSeenStructure)
+ return m_observedArrayModes | arrayModeFromStructure(m_lastSeenStructure);
+ return m_observedArrayModes;
+}
+
void ArrayProfile::computeUpdatedPrediction(CodeBlock* codeBlock, OperationInProgress operation)
{
if (m_lastSeenStructure) {
diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.h b/Source/JavaScriptCore/bytecode/ArrayProfile.h
index 376684fc1..5116cd36f 100644
--- a/Source/JavaScriptCore/bytecode/ArrayProfile.h
+++ b/Source/JavaScriptCore/bytecode/ArrayProfile.h
@@ -45,15 +45,20 @@ typedef unsigned ArrayModes;
#define ALL_NON_ARRAY_ARRAY_MODES \
(asArrayModes(NonArray) \
- | asArrayModes(NonArrayWithContiguous) \
- | asArrayModes(NonArrayWithArrayStorage) \
- | asArrayModes(NonArrayWithSlowPutArrayStorage))
+ | asArrayModes(NonArrayWithInt32) \
+ | asArrayModes(NonArrayWithDouble) \
+ | asArrayModes(NonArrayWithContiguous) \
+ | asArrayModes(NonArrayWithArrayStorage) \
+ | asArrayModes(NonArrayWithSlowPutArrayStorage))
#define ALL_ARRAY_ARRAY_MODES \
(asArrayModes(ArrayClass) \
- | asArrayModes(ArrayWithContiguous) \
- | asArrayModes(ArrayWithArrayStorage) \
- | asArrayModes(ArrayWithSlowPutArrayStorage))
+ | asArrayModes(ArrayWithUndecided) \
+ | asArrayModes(ArrayWithInt32) \
+ | asArrayModes(ArrayWithDouble) \
+ | asArrayModes(ArrayWithContiguous) \
+ | asArrayModes(ArrayWithArrayStorage) \
+ | asArrayModes(ArrayWithSlowPutArrayStorage))
#define ALL_ARRAY_MODES (ALL_NON_ARRAY_ARRAY_MODES | ALL_ARRAY_ARRAY_MODES)
@@ -79,6 +84,36 @@ inline bool arrayModesAlreadyChecked(ArrayModes proven, ArrayModes expected)
return (expected | proven) == expected;
}
+inline bool arrayModesInclude(ArrayModes arrayModes, IndexingType shape)
+{
+ return !!(arrayModes & (asArrayModes(NonArray | shape) | asArrayModes(ArrayClass | shape)));
+}
+
+inline bool shouldUseSlowPutArrayStorage(ArrayModes arrayModes)
+{
+ return arrayModesInclude(arrayModes, SlowPutArrayStorageShape);
+}
+
+inline bool shouldUseFastArrayStorage(ArrayModes arrayModes)
+{
+ return arrayModesInclude(arrayModes, ArrayStorageShape);
+}
+
+inline bool shouldUseContiguous(ArrayModes arrayModes)
+{
+ return arrayModesInclude(arrayModes, ContiguousShape);
+}
+
+inline bool shouldUseDouble(ArrayModes arrayModes)
+{
+ return arrayModesInclude(arrayModes, DoubleShape);
+}
+
+inline bool shouldUseInt32(ArrayModes arrayModes)
+{
+ return arrayModesInclude(arrayModes, Int32Shape);
+}
+
class ArrayProfile {
public:
ArrayProfile()
@@ -128,6 +163,7 @@ public:
return !structureIsPolymorphic() && m_expectedStructure;
}
ArrayModes observedArrayModes() const { return m_observedArrayModes; }
+ ArrayModes updatedObservedArrayModes() const; // Computes the observed array modes without updating the profile.
bool mayInterceptIndexedAccesses() const { return m_mayInterceptIndexedAccesses; }
bool mayStoreToHole() const { return m_mayStoreToHole; }
diff --git a/Source/JavaScriptCore/bytecode/ByValInfo.h b/Source/JavaScriptCore/bytecode/ByValInfo.h
index 8cba4463d..3f79967df 100644
--- a/Source/JavaScriptCore/bytecode/ByValInfo.h
+++ b/Source/JavaScriptCore/bytecode/ByValInfo.h
@@ -39,6 +39,8 @@
namespace JSC {
enum JITArrayMode {
+ JITInt32,
+ JITDouble,
JITContiguous,
JITArrayStorage,
JITInt8Array,
@@ -55,6 +57,8 @@ enum JITArrayMode {
inline bool isOptimizableIndexingType(IndexingType indexingType)
{
switch (indexingType) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES:
return true;
@@ -77,6 +81,10 @@ inline bool hasOptimizableIndexing(Structure* structure)
inline JITArrayMode jitArrayModeForIndexingType(IndexingType indexingType)
{
switch (indexingType) {
+ case ALL_INT32_INDEXING_TYPES:
+ return JITInt32;
+ case ALL_DOUBLE_INDEXING_TYPES:
+ return JITDouble;
case ALL_CONTIGUOUS_INDEXING_TYPES:
return JITContiguous;
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES:
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index ceae3fcb2..83833c6ec 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -44,7 +44,7 @@
#include "JSValue.h"
#include "LowLevelInterpreter.h"
#include "RepatchBuffer.h"
-#include "SlotVisitorInlineMethods.h"
+#include "SlotVisitorInlines.h"
#include <stdio.h>
#include <wtf/StringExtras.h>
#include <wtf/UnusedParam.h>
@@ -654,6 +654,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int argc = (++it)->u.operand;
dataLog("[%4d] new_array\t %s, %s, %d", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc);
dumpBytecodeCommentAndNewLine(location);
+ ++it; // Skip array allocation profile.
break;
}
case op_new_array_with_size: {
@@ -661,6 +662,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int length = (++it)->u.operand;
dataLog("[%4d] new_array_with_size\t %s, %s", location, registerName(exec, dst).data(), registerName(exec, length).data());
dumpBytecodeCommentAndNewLine(location);
+ ++it; // Skip array allocation profile.
break;
}
case op_new_array_buffer: {
@@ -669,6 +671,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int argc = (++it)->u.operand;
dataLog("[%4d] new_array_buffer\t %s, %d, %d", location, registerName(exec, dst).data(), argv, argc);
dumpBytecodeCommentAndNewLine(location);
+ ++it; // Skip array allocation profile.
break;
}
case op_new_regexp: {
@@ -1746,6 +1749,8 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
#if ENABLE(DFG_JIT)
if (size_t size = unlinkedCodeBlock->numberOfArrayProfiles())
m_arrayProfiles.grow(size);
+ if (size_t size = unlinkedCodeBlock->numberOfArrayAllocationProfiles())
+ m_arrayAllocationProfiles.grow(size);
if (size_t size = unlinkedCodeBlock->numberOfValueProfiles())
m_valueProfiles.grow(size);
#endif
@@ -1800,19 +1805,32 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
break;
}
+ case op_new_array:
+ case op_new_array_buffer:
+ case op_new_array_with_size: {
+ int arrayAllocationProfileIndex = pc[i + opLength - 1].u.operand;
+ instructions[i + opLength - 1] = &m_arrayAllocationProfiles[arrayAllocationProfileIndex];
+ break;
+ }
+#endif
+
case op_call:
case op_call_eval: {
+#if ENABLE(DFG_JIT)
int arrayProfileIndex = pc[i + opLength - 1].u.operand;
m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i);
instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex];
- // fallthrough
- }
#endif
#if ENABLE(LLINT)
- case op_construct:
instructions[i + 4] = &m_llintCallLinkInfos[pc[i + 4].u.operand];
+#endif
break;
+ }
+ case op_construct:
+#if ENABLE(LLINT)
+ instructions[i + 4] = &m_llintCallLinkInfos[pc[i + 4].u.operand];
#endif
+ break;
case op_get_by_id_out_of_line:
case op_get_by_id_self:
case op_get_by_id_proto:
@@ -2787,18 +2805,28 @@ void CodeBlock::updateAllPredictionsAndCountLiveness(
#if ENABLE(DFG_JIT)
m_lazyOperandValueProfiles.computeUpdatedPredictions(operation);
#endif
-
- // Don't count the array profiles towards statistics, since each array profile
- // site also has a value profile site - so we already know whether or not it's
- // live.
+}
+
+void CodeBlock::updateAllValueProfilePredictions(OperationInProgress operation)
+{
+ unsigned ignoredValue1, ignoredValue2;
+ updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2);
+}
+
+void CodeBlock::updateAllArrayPredictions(OperationInProgress operation)
+{
for (unsigned i = m_arrayProfiles.size(); i--;)
m_arrayProfiles[i].computeUpdatedPrediction(this, operation);
+
+ // Don't count these either, for similar reasons.
+ for (unsigned i = m_arrayAllocationProfiles.size(); i--;)
+ m_arrayAllocationProfiles[i].updateIndexingType();
}
void CodeBlock::updateAllPredictions(OperationInProgress operation)
{
- unsigned ignoredValue1, ignoredValue2;
- updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2);
+ updateAllValueProfilePredictions(operation);
+ updateAllArrayPredictions(operation);
}
bool CodeBlock::shouldOptimizeNow()
@@ -2814,12 +2842,14 @@ bool CodeBlock::shouldOptimizeNow()
if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay())
return true;
+ updateAllArrayPredictions();
+
unsigned numberOfLiveNonArgumentValueProfiles;
unsigned numberOfSamplesInProfiles;
updateAllPredictionsAndCountLiveness(NoOperation, numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles);
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles());
+ dataLog("Profile hotness: %lf (%u / %u), %lf (%u / %u)\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), numberOfLiveNonArgumentValueProfiles, numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles(), numberOfSamplesInProfiles, ValueProfile::numberOfBuckets * numberOfValueProfiles());
#endif
if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles() >= Options::desiredProfileLivenessRate())
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index a28064940..0199935bb 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -755,6 +755,13 @@ namespace JSC {
}
ArrayProfile* getArrayProfile(unsigned bytecodeOffset);
ArrayProfile* getOrAddArrayProfile(unsigned bytecodeOffset);
+
+ unsigned numberOfArrayAllocationProfiles() const { return m_arrayAllocationProfiles.size(); }
+ ArrayAllocationProfile* addArrayAllocationProfile()
+ {
+ m_arrayAllocationProfiles.append(ArrayAllocationProfile());
+ return &m_arrayAllocationProfiles.last();
+ }
#endif
// Exception handling support
@@ -1145,9 +1152,13 @@ namespace JSC {
#if ENABLE(VALUE_PROFILER)
bool shouldOptimizeNow();
+ void updateAllValueProfilePredictions(OperationInProgress = NoOperation);
+ void updateAllArrayPredictions(OperationInProgress = NoOperation);
void updateAllPredictions(OperationInProgress = NoOperation);
#else
bool shouldOptimizeNow() { return false; }
+ void updateAllValueProfilePredictions(OperationInProgress = NoOperation) { }
+ void updateAllArrayPredictions(OperationInProgress = NoOperation) { }
void updateAllPredictions(OperationInProgress = NoOperation) { }
#endif
@@ -1330,6 +1341,7 @@ namespace JSC {
SegmentedVector<ValueProfile, 8> m_valueProfiles;
SegmentedVector<RareCaseProfile, 8> m_rareCaseProfiles;
SegmentedVector<RareCaseProfile, 8> m_specialFastCaseProfiles;
+ SegmentedVector<ArrayAllocationProfile, 8> m_arrayAllocationProfiles;
ArrayProfileVector m_arrayProfiles;
unsigned m_executionEntryCount;
#endif
diff --git a/Source/JavaScriptCore/bytecode/DFGExitProfile.h b/Source/JavaScriptCore/bytecode/DFGExitProfile.h
index 60d313ad4..7132adfd4 100644
--- a/Source/JavaScriptCore/bytecode/DFGExitProfile.h
+++ b/Source/JavaScriptCore/bytecode/DFGExitProfile.h
@@ -58,6 +58,8 @@ inline const char* exitKindToString(ExitKind kind)
return "BadCache";
case BadWeakConstantCache:
return "BadWeakConstantCache";
+ case BadIndexingType:
+ return "BadIndexingType";
case Overflow:
return "Overflow";
case NegativeZero:
diff --git a/Source/JavaScriptCore/bytecode/Instruction.h b/Source/JavaScriptCore/bytecode/Instruction.h
index 9fcf509f6..50b80e03c 100644
--- a/Source/JavaScriptCore/bytecode/Instruction.h
+++ b/Source/JavaScriptCore/bytecode/Instruction.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -47,6 +47,7 @@ namespace JSC {
// curently actually use PolymorphicAccessStructureLists, which we should). Anyway, this seems like the best
// solution for now - will need to something smarter if/when we actually want mixed-mode operation.
+ class ArrayAllocationProfile;
class ArrayProfile;
class JSCell;
class Structure;
@@ -193,6 +194,7 @@ namespace JSC {
Instruction(ValueProfile* profile) { u.profile = profile; }
Instruction(ArrayProfile* profile) { u.arrayProfile = profile; }
+ Instruction(ArrayAllocationProfile* profile) { u.arrayAllocationProfile = profile; }
Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; }
@@ -212,6 +214,7 @@ namespace JSC {
LLIntCallLinkInfo* callLinkInfo;
ValueProfile* profile;
ArrayProfile* arrayProfile;
+ ArrayAllocationProfile* arrayAllocationProfile;
void* pointer;
bool* predicatePointer;
} u;
diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h
index 8979d0b7b..38d314d78 100644
--- a/Source/JavaScriptCore/bytecode/Opcode.h
+++ b/Source/JavaScriptCore/bytecode/Opcode.h
@@ -48,9 +48,9 @@ namespace JSC {
macro(op_convert_this, 3) \
\
macro(op_new_object, 2) \
- macro(op_new_array, 4) \
- macro(op_new_array_with_size, 3) \
- macro(op_new_array_buffer, 4) \
+ macro(op_new_array, 5) \
+ macro(op_new_array_with_size, 4) \
+ macro(op_new_array_buffer, 5) \
macro(op_new_regexp, 3) \
macro(op_mov, 3) \
\
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h
index 09ba9fdfa..656bc79ee 100644
--- a/Source/JavaScriptCore/bytecode/SpeculatedType.h
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h
@@ -61,6 +61,7 @@ static const SpeculatedType SpecInt32 = 0x00800000; // It's definite
static const SpeculatedType SpecDoubleReal = 0x01000000; // It's definitely a non-NaN double.
static const SpeculatedType SpecDoubleNaN = 0x02000000; // It's definitely a NaN.
static const SpeculatedType SpecDouble = 0x03000000; // It's either a non-NaN or a NaN double.
+static const SpeculatedType SpecRealNumber = 0x01800000; // It's either an Int32 or a DoubleReal.
static const SpeculatedType SpecNumber = 0x03800000; // It's either an Int32 or a Double.
static const SpeculatedType SpecBoolean = 0x04000000; // It's definitely a Boolean.
static const SpeculatedType SpecOther = 0x08000000; // It's definitely none of the above.
@@ -228,6 +229,16 @@ inline bool isInt32Speculation(SpeculatedType value)
return value == SpecInt32;
}
+inline bool isInt32SpeculationForArithmetic(SpeculatedType value)
+{
+ return !(value & SpecDouble);
+}
+
+inline bool isInt32SpeculationExpectingDefined(SpeculatedType value)
+{
+ return isInt32Speculation(value & ~SpecOther);
+}
+
inline bool isDoubleRealSpeculation(SpeculatedType value)
{
return value == SpecDoubleReal;
@@ -238,11 +249,26 @@ inline bool isDoubleSpeculation(SpeculatedType value)
return !!value && (value & SpecDouble) == value;
}
+inline bool isDoubleSpeculationForArithmetic(SpeculatedType value)
+{
+ return !!(value & SpecDouble);
+}
+
+inline bool isRealNumberSpeculation(SpeculatedType value)
+{
+ return !!(value & SpecRealNumber) && !(value & ~SpecRealNumber);
+}
+
inline bool isNumberSpeculation(SpeculatedType value)
{
return !!(value & SpecNumber) && !(value & ~SpecNumber);
}
+inline bool isNumberSpeculationExpectingDefined(SpeculatedType value)
+{
+ return isNumberSpeculation(value & ~SpecOther);
+}
+
inline bool isBooleanSpeculation(SpeculatedType value)
{
return value == SpecBoolean;
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
index 8aa48404a..e98d4de0a 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
@@ -80,8 +80,6 @@ void UnlinkedFunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visito
COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
Base::visitChildren(thisObject, visitor);
- visitor.append(&thisObject->m_codeBlockForCall);
- visitor.append(&thisObject->m_codeBlockForConstruct);
visitor.append(&thisObject->m_nameValue);
visitor.append(&thisObject->m_symbolTableForCall);
visitor.append(&thisObject->m_symbolTableForConstruct);
@@ -112,12 +110,16 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData
{
switch (specializationKind) {
case CodeForCall:
- if (m_codeBlockForCall)
- return m_codeBlockForCall.get();
+ if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForCall.get()) {
+ globalData.codeCache()->usedFunctionCode(globalData, codeBlock);
+ return codeBlock;
+ }
break;
case CodeForConstruct:
- if (m_codeBlockForConstruct)
- return m_codeBlockForConstruct.get();
+ if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForConstruct.get()) {
+ globalData.codeCache()->usedFunctionCode(globalData, codeBlock);
+ return codeBlock;
+ }
break;
}
@@ -128,11 +130,11 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData
switch (specializationKind) {
case CodeForCall:
- m_codeBlockForCall.set(globalData, this, result);
+ m_codeBlockForCall = PassWeak<UnlinkedFunctionCodeBlock>(result);
m_symbolTableForCall.set(globalData, this, result->symbolTable());
break;
case CodeForConstruct:
- m_codeBlockForConstruct.set(globalData, this, result);
+ m_codeBlockForConstruct = PassWeak<UnlinkedFunctionCodeBlock>(result);
m_symbolTableForConstruct.set(globalData, this, result->symbolTable());
break;
}
@@ -171,6 +173,7 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(JSGlobalData* globalData, Structure* struct
, m_resolveOperationCount(0)
, m_putToBaseOperationCount(1)
, m_arrayProfileCount(0)
+ , m_arrayAllocationProfileCount(0)
, m_valueProfileCount(0)
, m_llintCallLinkInfoCount(0)
#if ENABLE(BYTECODE_COMMENTS)
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
index bf3f5fdff..23937d773 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
@@ -36,6 +36,7 @@
#include "Nodes.h"
#include "RegExp.h"
#include "SpecialPointer.h"
+#include "Weak.h"
#include <wtf/RefCountedArray.h>
#include <wtf/Vector.h>
@@ -56,6 +57,7 @@ class UnlinkedFunctionCodeBlock;
typedef unsigned UnlinkedValueProfile;
typedef unsigned UnlinkedArrayProfile;
+typedef unsigned UnlinkedArrayAllocationProfile;
typedef unsigned UnlinkedLLIntCallLinkInfo;
struct ExecutableInfo {
@@ -107,7 +109,7 @@ public:
FunctionExecutable* link(JSGlobalData&, const SourceCode&, size_t lineOffset, size_t sourceOffset);
- void clearCode()
+ void clearCodeForRecompilation()
{
m_symbolTableForCall.clear();
m_symbolTableForConstruct.clear();
@@ -135,8 +137,8 @@ public:
private:
UnlinkedFunctionExecutable(JSGlobalData*, Structure*, const SourceCode&, FunctionBodyNode*);
- WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForCall;
- WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct;
+ Weak<UnlinkedFunctionCodeBlock> m_codeBlockForCall;
+ Weak<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct;
unsigned m_numCapturedVariables : 29;
bool m_forceUsesArguments : 1;
@@ -392,6 +394,8 @@ public:
UnlinkedArrayProfile addArrayProfile() { return m_arrayProfileCount++; }
unsigned numberOfArrayProfiles() { return m_arrayProfileCount; }
+ UnlinkedArrayAllocationProfile addArrayAllocationProfile() { return m_arrayAllocationProfileCount++; }
+ unsigned numberOfArrayAllocationProfiles() { return m_arrayAllocationProfileCount; }
UnlinkedValueProfile addValueProfile() { return m_valueProfileCount++; }
unsigned numberOfValueProfiles() { return m_valueProfileCount; }
@@ -518,6 +522,7 @@ private:
unsigned m_resolveOperationCount;
unsigned m_putToBaseOperationCount;
unsigned m_arrayProfileCount;
+ unsigned m_arrayAllocationProfileCount;
unsigned m_valueProfileCount;
unsigned m_llintCallLinkInfoCount;
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index b11872551..b1b9de6c1 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -716,6 +716,15 @@ UnlinkedArrayProfile BytecodeGenerator::newArrayProfile()
#endif
}
+UnlinkedArrayAllocationProfile BytecodeGenerator::newArrayAllocationProfile()
+{
+#if ENABLE(VALUE_PROFILER)
+ return m_codeBlock->addArrayAllocationProfile();
+#else
+ return 0;
+#endif
+}
+
UnlinkedValueProfile BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID)
{
#if ENABLE(VALUE_PROFILER)
@@ -1605,6 +1614,7 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen
instructions().append(dst->index());
instructions().append(constantBufferIndex);
instructions().append(length);
+ instructions().append(newArrayAllocationProfile());
return dst;
}
}
@@ -1622,6 +1632,7 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen
instructions().append(dst->index());
instructions().append(argv.size() ? argv[0]->index() : 0); // argv
instructions().append(argv.size()); // argc
+ instructions().append(newArrayAllocationProfile());
return dst;
}
@@ -1757,12 +1768,14 @@ ExpectedFunction BytecodeGenerator::emitExpectedFunctionSnippet(RegisterID* dst,
emitOpcode(op_new_array_with_size);
instructions().append(dst->index());
instructions().append(callArguments.argumentRegister(0)->index());
+ instructions().append(newArrayAllocationProfile());
} else {
ASSERT(callArguments.argumentCountIncludingThis() == 1);
emitOpcode(op_new_array);
instructions().append(dst->index());
instructions().append(0);
instructions().append(0);
+ instructions().append(newArrayAllocationProfile());
}
}
break;
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 828726dee..2e7aa2035 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -523,6 +523,7 @@ namespace JSC {
#endif
void emitOpcode(OpcodeID);
+ UnlinkedArrayAllocationProfile newArrayAllocationProfile();
UnlinkedArrayProfile newArrayProfile();
UnlinkedValueProfile emitProfiledOpcode(OpcodeID);
void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index);
diff --git a/Source/JavaScriptCore/debugger/Debugger.cpp b/Source/JavaScriptCore/debugger/Debugger.cpp
index b14729146..7eda52dc8 100644
--- a/Source/JavaScriptCore/debugger/Debugger.cpp
+++ b/Source/JavaScriptCore/debugger/Debugger.cpp
@@ -80,7 +80,7 @@ inline void Recompiler::operator()(JSCell* cell)
ExecState* exec = function->scope()->globalObject()->JSGlobalObject::globalExec();
executable->clearCodeIfNotCompiling();
- executable->clearUnlinkedCodeIfNotCompiling();
+ executable->clearUnlinkedCodeForRecompilationIfNotCompiling();
if (m_debugger == function->scope()->globalObject()->debugger())
m_sourceProviders.add(executable->source().provider(), exec);
}
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index e518c24a8..02e578b29 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -159,7 +159,7 @@ void AbstractState::initialize(Graph& graph)
}
}
-bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDirectionPtr)
+bool AbstractState::endBasicBlock(MergeMode mergeMode)
{
ASSERT(m_block);
@@ -167,6 +167,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi
block->cfaFoundConstants = m_foundConstants;
block->cfaDidFinish = m_isValid;
+ block->cfaBranchDirection = m_branchDirection;
if (!m_isValid) {
reset();
@@ -195,12 +196,8 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi
ASSERT(mergeMode != DontMerge || !changed);
- BranchDirection branchDirection = m_branchDirection;
- if (branchDirectionPtr)
- *branchDirectionPtr = branchDirection;
-
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Branch direction = %s\n", branchDirectionToString(branchDirection));
+ dataLog(" Branch direction = %s\n", branchDirectionToString(m_branchDirection));
#endif
reset();
@@ -208,7 +205,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi
if (mergeMode != MergeToSuccessors)
return changed;
- return mergeToSuccessors(m_graph, block, branchDirection);
+ return mergeToSuccessors(m_graph, block);
}
void AbstractState::reset()
@@ -424,7 +421,10 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
}
speculateNumberUnary(node);
- forNode(nodeIndex).set(SpecDouble);
+ if (isInt32Speculation(forNode(node.child1()).m_type))
+ forNode(nodeIndex).set(SpecDoubleReal);
+ else
+ forNode(nodeIndex).set(SpecDouble);
break;
}
@@ -448,9 +448,13 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(nodeIndex).set(SpecInt32);
break;
}
- if (Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()])) {
+ if (Node::shouldSpeculateNumberExpectingDefined(m_graph[node.child1()], m_graph[node.child2()])) {
speculateNumberBinary(node);
- forNode(nodeIndex).set(SpecDouble);
+ if (isRealNumberSpeculation(forNode(node.child1()).m_type)
+ && isRealNumberSpeculation(forNode(node.child2()).m_type))
+ forNode(nodeIndex).set(SpecDoubleReal);
+ else
+ forNode(nodeIndex).set(SpecDouble);
break;
}
if (node.op() == ValueAdd) {
@@ -522,7 +526,11 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
}
speculateNumberBinary(node);
- forNode(nodeIndex).set(SpecDouble);
+ if (isRealNumberSpeculation(forNode(node.child1()).m_type)
+ || isRealNumberSpeculation(forNode(node.child2()).m_type))
+ forNode(nodeIndex).set(SpecDoubleReal);
+ else
+ forNode(nodeIndex).set(SpecDouble);
break;
}
@@ -560,7 +568,7 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
}
}
- if (Node::shouldSpeculateInteger(
+ if (Node::shouldSpeculateIntegerForArithmetic(
m_graph[node.child1()], m_graph[node.child2()])
&& node.canSpeculateInteger()) {
speculateInt32Binary(node, true); // forcing can-exit, which is a bit on the conservative side.
@@ -580,7 +588,7 @@ bool AbstractState::execute(unsigned indexInBlock)
node.setCanExit(false);
break;
}
- if (m_graph[node.child1()].shouldSpeculateInteger()
+ if (m_graph[node.child1()].shouldSpeculateIntegerForArithmetic()
&& node.canSpeculateInteger()) {
speculateInt32Unary(node, true);
forNode(nodeIndex).set(SpecInt32);
@@ -605,12 +613,22 @@ bool AbstractState::execute(unsigned indexInBlock)
}
case LogicalNot: {
+ // First check if we can fold because the source is a constant.
JSValue childConst = forNode(node.child1()).value();
if (childConst && trySetConstant(nodeIndex, jsBoolean(!childConst.toBoolean(m_codeBlock->globalObjectFor(node.codeOrigin)->globalExec())))) {
m_foundConstants = true;
node.setCanExit(false);
break;
}
+ // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
+ if (isCellSpeculation(forNode(node.child1()).m_type)
+ && forNode(node.child1()).m_currentKnownStructure.hasSingleton()
+ && !forNode(node.child1()).m_currentKnownStructure.singleton()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node.codeOrigin))
+ && trySetConstant(nodeIndex, jsBoolean(false))) {
+ m_foundConstants = true;
+ node.setCanExit(false);
+ break;
+ }
Node& child = m_graph[node.child1()];
if (isBooleanSpeculation(child.prediction()))
speculateBooleanUnary(node);
@@ -678,12 +696,13 @@ bool AbstractState::execute(unsigned indexInBlock)
case CompareGreater:
case CompareGreaterEq:
case CompareEq: {
+ bool constantWasSet = false;
+
JSValue leftConst = forNode(node.child1()).value();
JSValue rightConst = forNode(node.child2()).value();
if (leftConst && rightConst && leftConst.isNumber() && rightConst.isNumber()) {
double a = leftConst.asNumber();
double b = rightConst.asNumber();
- bool constantWasSet;
switch (node.op()) {
case CompareLess:
constantWasSet = trySetConstant(nodeIndex, jsBoolean(a < b));
@@ -705,11 +724,20 @@ bool AbstractState::execute(unsigned indexInBlock)
constantWasSet = false;
break;
}
- if (constantWasSet) {
- m_foundConstants = true;
- node.setCanExit(false);
- break;
- }
+ }
+
+ if (!constantWasSet && node.op() == CompareEq) {
+ SpeculatedType leftType = forNode(node.child1()).m_type;
+ SpeculatedType rightType = forNode(node.child2()).m_type;
+ if ((isInt32Speculation(leftType) && isOtherSpeculation(rightType))
+ || (isOtherSpeculation(leftType) && isInt32Speculation(rightType)))
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(false));
+ }
+
+ if (constantWasSet) {
+ m_foundConstants = true;
+ node.setCanExit(false);
+ break;
}
forNode(nodeIndex).set(SpecBoolean);
@@ -842,6 +870,7 @@ bool AbstractState::execute(unsigned indexInBlock)
switch (node.arrayMode().type()) {
case Array::SelectUsingPredictions:
case Array::Unprofiled:
+ case Array::Undecided:
ASSERT_NOT_REACHED();
break;
case Array::ForceExit:
@@ -859,6 +888,22 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).makeTop();
break;
+ case Array::Int32:
+ forNode(node.child2()).filter(SpecInt32);
+ if (node.arrayMode().isOutOfBounds()) {
+ clobberWorld(node.codeOrigin, indexInBlock);
+ forNode(nodeIndex).makeTop();
+ } else
+ forNode(nodeIndex).set(SpecInt32);
+ break;
+ case Array::Double:
+ forNode(node.child2()).filter(SpecInt32);
+ if (node.arrayMode().isOutOfBounds()) {
+ clobberWorld(node.codeOrigin, indexInBlock);
+ forNode(nodeIndex).makeTop();
+ } else
+ forNode(nodeIndex).set(SpecDoubleReal);
+ break;
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
@@ -926,6 +971,20 @@ bool AbstractState::execute(unsigned indexInBlock)
case Array::Generic:
clobberWorld(node.codeOrigin, indexInBlock);
break;
+ case Array::Int32:
+ forNode(child1).filter(SpecCell);
+ forNode(child2).filter(SpecInt32);
+ forNode(child3).filter(SpecInt32);
+ if (node.arrayMode().isOutOfBounds())
+ clobberWorld(node.codeOrigin, indexInBlock);
+ break;
+ case Array::Double:
+ forNode(child1).filter(SpecCell);
+ forNode(child2).filter(SpecInt32);
+ forNode(child3).filter(SpecRealNumber);
+ if (node.arrayMode().isOutOfBounds())
+ clobberWorld(node.codeOrigin, indexInBlock);
+ break;
case Array::Contiguous:
case Array::ArrayStorage:
forNode(child1).filter(SpecCell);
@@ -1018,6 +1077,16 @@ bool AbstractState::execute(unsigned indexInBlock)
case ArrayPush:
node.setCanExit(true);
+ switch (node.arrayMode().type()) {
+ case Array::Int32:
+ forNode(node.child2()).filter(SpecInt32);
+ break;
+ case Array::Double:
+ forNode(node.child2()).filter(SpecRealNumber);
+ break;
+ default:
+ break;
+ }
clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).set(SpecNumber);
break;
@@ -1043,6 +1112,7 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
case Branch: {
+ // First check if we can fold because the source is a constant.
JSValue value = forNode(node.child1()).value();
if (value) {
bool booleanValue = value.toBoolean(m_codeBlock->globalObjectFor(node.codeOrigin)->globalExec());
@@ -1053,6 +1123,14 @@ bool AbstractState::execute(unsigned indexInBlock)
node.setCanExit(false);
break;
}
+ // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
+ if (isCellSpeculation(forNode(node.child1()).m_type)
+ && forNode(node.child1()).m_currentKnownStructure.hasSingleton()
+ && !forNode(node.child1()).m_currentKnownStructure.singleton()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node.codeOrigin))) {
+ m_branchDirection = TakeTrue;
+ node.setCanExit(false);
+ break;
+ }
// FIXME: The above handles the trivial cases of sparse conditional
// constant propagation, but we can do better:
// 1) If the abstract value does not have a concrete value but describes
@@ -1122,13 +1200,13 @@ bool AbstractState::execute(unsigned indexInBlock)
case NewArray:
node.setCanExit(true);
- forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure());
+ forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()));
m_haveStructures = true;
break;
case NewArrayBuffer:
node.setCanExit(true);
- forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure());
+ forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()));
m_haveStructures = true;
break;
@@ -1384,11 +1462,11 @@ bool AbstractState::execute(unsigned indexInBlock)
case Array::String:
forNode(node.child1()).filter(SpecString);
break;
+ case Array::Int32:
+ case Array::Double:
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
- // This doesn't filter anything meaningful right now. We may want to add
- // CFA tracking of array mode speculations, but we don't have that, yet.
forNode(node.child1()).filter(SpecCell);
break;
case Array::Arguments:
@@ -1722,7 +1800,7 @@ inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to)
}
inline bool AbstractState::mergeToSuccessors(
- Graph& graph, BasicBlock* basicBlock, BranchDirection branchDirection)
+ Graph& graph, BasicBlock* basicBlock)
{
Node& terminal = graph[basicBlock->last()];
@@ -1730,7 +1808,7 @@ inline bool AbstractState::mergeToSuccessors(
switch (terminal.op()) {
case Jump: {
- ASSERT(branchDirection == InvalidBranchDirection);
+ ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Merging to block #%u.\n", terminal.takenBlockIndex());
#endif
@@ -1738,17 +1816,17 @@ inline bool AbstractState::mergeToSuccessors(
}
case Branch: {
- ASSERT(branchDirection != InvalidBranchDirection);
+ ASSERT(basicBlock->cfaBranchDirection != InvalidBranchDirection);
bool changed = false;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Merging to block #%u.\n", terminal.takenBlockIndex());
#endif
- if (branchDirection != TakeFalse)
+ if (basicBlock->cfaBranchDirection != TakeFalse)
changed |= merge(basicBlock, graph.m_blocks[terminal.takenBlockIndex()].get());
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Merging to block #%u.\n", terminal.notTakenBlockIndex());
#endif
- if (branchDirection != TakeTrue)
+ if (basicBlock->cfaBranchDirection != TakeTrue)
changed |= merge(basicBlock, graph.m_blocks[terminal.notTakenBlockIndex()].get());
return changed;
}
@@ -1756,7 +1834,7 @@ inline bool AbstractState::mergeToSuccessors(
case Return:
case Throw:
case ThrowReferenceError:
- ASSERT(branchDirection == InvalidBranchDirection);
+ ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
return false;
default:
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h
index ec1a06231..0e33140c0 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,6 +31,7 @@
#if ENABLE(DFG_JIT)
#include "DFGAbstractValue.h"
+#include "DFGBranchDirection.h"
#include "DFGGraph.h"
#include "DFGNode.h"
#include <wtf/Vector.h>
@@ -92,36 +93,6 @@ public:
MergeToSuccessors
};
- enum BranchDirection {
- // This is not a branch and so there is no branch direction, or
- // the branch direction has yet to be set.
- InvalidBranchDirection,
-
- // The branch takes the true case.
- TakeTrue,
-
- // The branch takes the false case.
- TakeFalse,
-
- // For all we know, the branch could go either direction, so we
- // have to assume the worst.
- TakeBoth
- };
-
- static const char* branchDirectionToString(BranchDirection branchDirection)
- {
- switch (branchDirection) {
- case InvalidBranchDirection:
- return "Invalid";
- case TakeTrue:
- return "TakeTrue";
- case TakeFalse:
- return "TakeFalse";
- case TakeBoth:
- return "TakeBoth";
- }
- }
-
AbstractState(Graph&);
~AbstractState();
@@ -174,11 +145,7 @@ public:
// A true return means that you must revisit (at least) the successor
// blocks. This also sets cfaShouldRevisit to true for basic blocks
// that must be visited next.
- //
- // If you'd like to know what direction the branch at the end of the
- // basic block is thought to have taken, you can pass a non-0 pointer
- // for BranchDirection.
- bool endBasicBlock(MergeMode, BranchDirection* = 0);
+ bool endBasicBlock(MergeMode);
// Reset the AbstractState. This throws away any results, and at this point
// you can safely call beginBasicBlock() on any basic block.
@@ -211,8 +178,8 @@ public:
// successors. Returns true if any of the successors' states changed. Note
// that this is automatically called in endBasicBlock() if MergeMode is
// MergeToSuccessors.
- bool mergeToSuccessors(Graph&, BasicBlock*, BranchDirection);
-
+ bool mergeToSuccessors(Graph&, BasicBlock*);
+
void dump(FILE* out);
private:
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
index 699902a16..0d15b9a30 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
@@ -34,19 +34,46 @@ namespace JSC { namespace DFG {
ArrayMode ArrayMode::fromObserved(ArrayProfile* profile, Array::Action action, bool makeSafe)
{
- switch (profile->observedArrayModes()) {
+ ArrayModes observed = profile->observedArrayModes();
+ switch (observed) {
case 0:
return ArrayMode(Array::Unprofiled);
case asArrayModes(NonArray):
if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
- return ArrayMode(Array::Contiguous, Array::NonArray, Array::OutOfBounds, Array::Convert); // FIXME: we don't know whether to go to contiguous or array storage. We're making a static guess here. In future we should use exit profiling for this.
+ return ArrayMode(Array::Undecided, Array::NonArray, Array::OutOfBounds, Array::Convert);
return ArrayMode(Array::SelectUsingPredictions);
+
+ case asArrayModes(ArrayWithUndecided):
+ if (action == Array::Write)
+ return ArrayMode(Array::Undecided, Array::Array, Array::OutOfBounds, Array::Convert);
+ return ArrayMode(Array::Generic);
+
+ case asArrayModes(NonArray) | asArrayModes(ArrayWithUndecided):
+ if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
+ return ArrayMode(Array::Undecided, Array::PossiblyArray, Array::OutOfBounds, Array::Convert);
+ return ArrayMode(Array::SelectUsingPredictions);
+
+ case asArrayModes(NonArrayWithInt32):
+ return ArrayMode(Array::Int32, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+ case asArrayModes(ArrayWithInt32):
+ return ArrayMode(Array::Int32, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+ case asArrayModes(NonArrayWithInt32) | asArrayModes(ArrayWithInt32):
+ return ArrayMode(Array::Int32, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+
+ case asArrayModes(NonArrayWithDouble):
+ return ArrayMode(Array::Double, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+ case asArrayModes(ArrayWithDouble):
+ return ArrayMode(Array::Double, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+ case asArrayModes(NonArrayWithDouble) | asArrayModes(ArrayWithDouble):
+ return ArrayMode(Array::Double, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+
case asArrayModes(NonArrayWithContiguous):
return ArrayMode(Array::Contiguous, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
case asArrayModes(ArrayWithContiguous):
return ArrayMode(Array::Contiguous, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
case asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous):
return ArrayMode(Array::Contiguous, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+
case asArrayModes(NonArrayWithArrayStorage):
return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
case asArrayModes(NonArrayWithSlowPutArrayStorage):
@@ -62,36 +89,39 @@ ArrayMode ArrayMode::fromObserved(ArrayProfile* profile, Array::Action action, b
case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
- case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage):
- return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::Convert).withProfile(profile, makeSafe);
- case asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage):
- return ArrayMode(Array::ArrayStorage, Array::Array, Array::Convert).withProfile(profile, makeSafe);
- case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage):
- return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::Convert).withProfile(profile, makeSafe);
- case asArrayModes(NonArray) | asArrayModes(NonArrayWithContiguous):
- if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
- return ArrayMode(Array::Contiguous, Array::NonArray, Array::OutOfBounds, Array::Convert);
- return ArrayMode(Array::SelectUsingPredictions);
- case asArrayModes(NonArray) | asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage):
- case asArrayModes(NonArray) | asArrayModes(NonArrayWithArrayStorage):
- if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
- return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::OutOfBounds, Array::Convert);
- return ArrayMode(Array::SelectUsingPredictions);
- case asArrayModes(NonArray) | asArrayModes(NonArrayWithSlowPutArrayStorage):
- case asArrayModes(NonArray) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage):
- if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
- return ArrayMode(Array::SlowPutArrayStorage, Array::NonArray, Array::OutOfBounds, Array::Convert);
- return ArrayMode(Array::SelectUsingPredictions);
+
default:
- // We know that this is possibly a kind of array for which, though there is no
- // useful data in the array profile, we may be able to extract useful data from
- // the value profiles of the inputs. Hence, we leave it as undecided, and let
- // the predictions propagator decide later.
- return ArrayMode(Array::SelectUsingPredictions);
+ if ((observed & asArrayModes(NonArray)) && profile->mayInterceptIndexedAccesses())
+ return ArrayMode(Array::SelectUsingPredictions);
+
+ Array::Type type;
+ Array::Class arrayClass;
+
+ if (shouldUseSlowPutArrayStorage(observed))
+ type = Array::SlowPutArrayStorage;
+ else if (shouldUseFastArrayStorage(observed))
+ type = Array::ArrayStorage;
+ else if (shouldUseContiguous(observed))
+ type = Array::Contiguous;
+ else if (shouldUseDouble(observed))
+ type = Array::Double;
+ else if (shouldUseInt32(observed))
+ type = Array::Int32;
+ else
+ type = Array::Undecided;
+
+ if (observed & (asArrayModes(ArrayWithUndecided) | asArrayModes(ArrayWithInt32) | asArrayModes(ArrayWithDouble) | asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
+ arrayClass = Array::Array;
+ else if (observed & (asArrayModes(NonArray) | asArrayModes(NonArrayWithInt32) | asArrayModes(NonArrayWithDouble) | asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage)))
+ arrayClass = Array::NonArray;
+ else
+ arrayClass = Array::PossiblyArray;
+
+ return ArrayMode(type, arrayClass, Array::Convert).withProfile(profile, makeSafe);
}
}
-ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index) const
+ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, SpeculatedType value) const
{
if (!base || !index) {
// It can be that we had a legitimate arrayMode but no incoming predictions. That'll
@@ -104,49 +134,85 @@ ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index) const
if (!isInt32Speculation(index) || !isCellSpeculation(base))
return ArrayMode(Array::Generic);
- if (type() == Array::Unprofiled) {
- // If the indexing type wasn't recorded in the array profile but the values are
- // base=cell property=int, then we know that this access didn't execute.
+ switch (type()) {
+ case Array::Unprofiled:
return ArrayMode(Array::ForceExit);
- }
-
- if (type() != Array::SelectUsingPredictions)
+
+ case Array::Undecided:
+ if (!value)
+ return withType(Array::ForceExit);
+ if (isInt32Speculation(value))
+ return withTypeAndConversion(Array::Int32, Array::Convert);
+ if (isNumberSpeculation(value))
+ return withTypeAndConversion(Array::Double, Array::Convert);
+ return withTypeAndConversion(Array::Contiguous, Array::Convert);
+
+ case Array::Int32:
+ if (!value || isInt32Speculation(value))
+ return *this;
+ if (isNumberSpeculation(value))
+ return withTypeAndConversion(Array::Double, Array::Convert);
+ return withTypeAndConversion(Array::Contiguous, Array::Convert);
+
+ case Array::Double:
+ if (!value || isNumberSpeculation(value))
+ return *this;
+ return withTypeAndConversion(Array::Contiguous, Array::Convert);
+
+ case Array::SelectUsingPredictions:
+ if (isStringSpeculation(base))
+ return ArrayMode(Array::String);
+
+ if (isArgumentsSpeculation(base))
+ return ArrayMode(Array::Arguments);
+
+ if (isInt8ArraySpeculation(base))
+ return ArrayMode(Array::Int8Array);
+
+ if (isInt16ArraySpeculation(base))
+ return ArrayMode(Array::Int16Array);
+
+ if (isInt32ArraySpeculation(base))
+ return ArrayMode(Array::Int32Array);
+
+ if (isUint8ArraySpeculation(base))
+ return ArrayMode(Array::Uint8Array);
+
+ if (isUint8ClampedArraySpeculation(base))
+ return ArrayMode(Array::Uint8ClampedArray);
+
+ if (isUint16ArraySpeculation(base))
+ return ArrayMode(Array::Uint16Array);
+
+ if (isUint32ArraySpeculation(base))
+ return ArrayMode(Array::Uint32Array);
+
+ if (isFloat32ArraySpeculation(base))
+ return ArrayMode(Array::Float32Array);
+
+ if (isFloat64ArraySpeculation(base))
+ return ArrayMode(Array::Float64Array);
+
+ return ArrayMode(Array::Generic);
+
+ default:
return *this;
-
- if (isStringSpeculation(base))
- return ArrayMode(Array::String);
-
- if (isArgumentsSpeculation(base))
- return ArrayMode(Array::Arguments);
-
- if (isInt8ArraySpeculation(base))
- return ArrayMode(Array::Int8Array);
-
- if (isInt16ArraySpeculation(base))
- return ArrayMode(Array::Int16Array);
-
- if (isInt32ArraySpeculation(base))
- return ArrayMode(Array::Int32Array);
-
- if (isUint8ArraySpeculation(base))
- return ArrayMode(Array::Uint8Array);
-
- if (isUint8ClampedArraySpeculation(base))
- return ArrayMode(Array::Uint8ClampedArray);
-
- if (isUint16ArraySpeculation(base))
- return ArrayMode(Array::Uint16Array);
-
- if (isUint32ArraySpeculation(base))
- return ArrayMode(Array::Uint32Array);
-
- if (isFloat32ArraySpeculation(base))
- return ArrayMode(Array::Float32Array);
-
- if (isFloat64ArraySpeculation(base))
- return ArrayMode(Array::Float64Array);
-
- return ArrayMode(Array::Generic);
+ }
+}
+
+bool ArrayMode::alreadyChecked(AbstractValue& value, IndexingType shape) const
+{
+ if (isJSArray()) {
+ if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape | IsArray)))
+ return true;
+ return value.m_currentKnownStructure.hasSingleton()
+ && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape
+ && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
+ }
+ if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape) | asArrayModes(shape | IsArray)))
+ return true;
+ return value.m_currentKnownStructure.hasSingleton()
+ && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape;
}
bool ArrayMode::alreadyChecked(AbstractValue& value) const
@@ -161,31 +227,17 @@ bool ArrayMode::alreadyChecked(AbstractValue& value) const
case Array::String:
return speculationChecked(value.m_type, SpecString);
+ case Array::Int32:
+ return alreadyChecked(value, Int32Shape);
+
+ case Array::Double:
+ return alreadyChecked(value, DoubleShape);
+
case Array::Contiguous:
- if (isJSArray()) {
- if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithContiguous)))
- return true;
- return value.m_currentKnownStructure.hasSingleton()
- && hasContiguous(value.m_currentKnownStructure.singleton()->indexingType())
- && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
- }
- if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous)))
- return true;
- return value.m_currentKnownStructure.hasSingleton()
- && hasContiguous(value.m_currentKnownStructure.singleton()->indexingType());
+ return alreadyChecked(value, ContiguousShape);
case Array::ArrayStorage:
- if (isJSArray()) {
- if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage)))
- return true;
- return value.m_currentKnownStructure.hasSingleton()
- && hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
- && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
- }
- if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage)))
- return true;
- return value.m_currentKnownStructure.hasSingleton()
- && hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
+ return alreadyChecked(value, ArrayStorageShape);
case Array::SlowPutArrayStorage:
if (isJSArray()) {
@@ -232,6 +284,7 @@ bool ArrayMode::alreadyChecked(AbstractValue& value) const
case Array::SelectUsingPredictions:
case Array::Unprofiled:
+ case Array::Undecided:
break;
}
@@ -252,6 +305,12 @@ const char* arrayTypeToString(Array::Type type)
return "ForceExit";
case Array::String:
return "String";
+ case Array::Undecided:
+ return "Undecided";
+ case Array::Int32:
+ return "Int32";
+ case Array::Double:
+ return "Double";
case Array::Contiguous:
return "Contiguous";
case Array::ArrayStorage:
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h
index 615965c92..206d689f2 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.h
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h
@@ -52,7 +52,10 @@ enum Type {
ForceExit, // Implies that we have no idea how to execute this operation, so we should just give up.
Generic,
String,
-
+
+ Undecided,
+ Int32,
+ Double,
Contiguous,
ArrayStorage,
SlowPutArrayStorage,
@@ -81,7 +84,6 @@ enum Speculation {
ToHole,
OutOfBounds
};
-
enum Conversion {
AsIs,
Convert
@@ -169,7 +171,17 @@ public:
return ArrayMode(type(), myArrayClass, mySpeculation, conversion());
}
- ArrayMode refine(SpeculatedType base, SpeculatedType index) const;
+ ArrayMode withType(Array::Type type) const
+ {
+ return ArrayMode(type, arrayClass(), speculation(), conversion());
+ }
+
+ ArrayMode withTypeAndConversion(Array::Type type, Array::Conversion conversion) const
+ {
+ return ArrayMode(type, arrayClass(), speculation(), conversion);
+ }
+
+ ArrayMode refine(SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone) const;
bool alreadyChecked(AbstractValue&) const;
@@ -178,6 +190,8 @@ public:
bool usesButterfly() const
{
switch (type()) {
+ case Array::Int32:
+ case Array::Double:
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
@@ -263,6 +277,7 @@ public:
case Array::Unprofiled:
case Array::ForceExit:
case Array::Generic:
+ case Array::Undecided:
return false;
default:
return true;
@@ -277,6 +292,8 @@ public:
case Array::ForceExit:
case Array::Generic:
return false;
+ case Array::Int32:
+ case Array::Double:
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
@@ -309,6 +326,10 @@ public:
switch (type()) {
case Array::Generic:
return ALL_ARRAY_MODES;
+ case Array::Int32:
+ return arrayModesWithIndexingShape(Int32Shape);
+ case Array::Double:
+ return arrayModesWithIndexingShape(DoubleShape);
case Array::Contiguous:
return arrayModesWithIndexingShape(ContiguousShape);
case Array::ArrayStorage:
@@ -354,6 +375,8 @@ private:
}
}
+ bool alreadyChecked(AbstractValue&, IndexingType shape) const;
+
union {
struct {
uint8_t type;
diff --git a/Source/JavaScriptCore/dfg/DFGBasicBlock.h b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
index 441e2e75e..6f348f2e1 100644
--- a/Source/JavaScriptCore/dfg/DFGBasicBlock.h
+++ b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
@@ -29,6 +29,7 @@
#if ENABLE(DFG_JIT)
#include "DFGAbstractValue.h"
+#include "DFGBranchDirection.h"
#include "DFGNode.h"
#include "Operands.h"
#include <wtf/OwnPtr.h>
@@ -46,6 +47,7 @@ struct BasicBlock : Vector<NodeIndex, 8> {
, cfaShouldRevisit(false)
, cfaFoundConstants(false)
, cfaDidFinish(true)
+ , cfaBranchDirection(InvalidBranchDirection)
#if !ASSERT_DISABLED
, isLinked(false)
#endif
@@ -105,6 +107,7 @@ struct BasicBlock : Vector<NodeIndex, 8> {
bool cfaShouldRevisit;
bool cfaFoundConstants;
bool cfaDidFinish;
+ BranchDirection cfaBranchDirection;
#if !ASSERT_DISABLED
bool isLinked;
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGBranchDirection.h b/Source/JavaScriptCore/dfg/DFGBranchDirection.h
new file mode 100644
index 000000000..8bbe3c635
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGBranchDirection.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGBranchDirection_h
+#define DFGBranchDirection_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+enum BranchDirection {
+ // This is not a branch and so there is no branch direction, or
+ // the branch direction has yet to be set.
+ InvalidBranchDirection,
+
+ // The branch takes the true case.
+ TakeTrue,
+
+ // The branch takes the false case.
+ TakeFalse,
+
+ // For all we know, the branch could go either direction, so we
+ // have to assume the worst.
+ TakeBoth
+};
+
+static inline const char* branchDirectionToString(BranchDirection branchDirection)
+{
+ switch (branchDirection) {
+ case InvalidBranchDirection:
+ return "Invalid";
+ case TakeTrue:
+ return "TakeTrue";
+ case TakeFalse:
+ return "TakeFalse";
+ case TakeBoth:
+ return "TakeBoth";
+ }
+}
+
+static inline bool isKnownDirection(BranchDirection branchDirection)
+{
+ switch (branchDirection) {
+ case TakeTrue:
+ case TakeFalse:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool branchCondition(BranchDirection branchDirection)
+{
+ if (branchDirection == TakeTrue)
+ return true;
+ ASSERT(branchDirection == TakeFalse);
+ return false;
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGBranchDirection_h
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 70aa2b637..142b8ab95 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -905,10 +905,15 @@ private:
return getPrediction(m_graph.size(), m_currentProfilingIndex);
}
- ArrayMode getArrayMode(ArrayProfile* profile)
+ ArrayMode getArrayMode(ArrayProfile* profile, Array::Action action)
{
profile->computeUpdatedPrediction(m_inlineStackTop->m_codeBlock);
- return ArrayMode::fromObserved(profile, Array::Read, false);
+ return ArrayMode::fromObserved(profile, action, false);
+ }
+
+ ArrayMode getArrayMode(ArrayProfile* profile)
+ {
+ return getArrayMode(profile, Array::Read);
}
ArrayMode getArrayModeAndEmitChecks(ArrayProfile* profile, Array::Action action, NodeIndex base)
@@ -1649,7 +1654,12 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
return false;
ArrayMode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile);
+ if (!arrayMode.isJSArray())
+ return false;
switch (arrayMode.type()) {
+ case Array::Undecided:
+ case Array::Int32:
+ case Array::Double:
case Array::Contiguous:
case Array::ArrayStorage: {
NodeIndex arrayPush = addToGraph(ArrayPush, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(registerOffset + argumentToOperand(0)), get(registerOffset + argumentToOperand(1)));
@@ -1669,7 +1679,11 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
return false;
ArrayMode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile);
+ if (!arrayMode.isJSArray())
+ return false;
switch (arrayMode.type()) {
+ case Array::Int32:
+ case Array::Double:
case Array::Contiguous:
case Array::ArrayStorage: {
NodeIndex arrayPop = addToGraph(ArrayPop, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(registerOffset + argumentToOperand(0)));
@@ -1754,7 +1768,7 @@ bool ByteCodeParser::handleConstantInternalFunction(
if (argumentCountIncludingThis == 2) {
setIntrinsicResult(
usesResult, resultOperand,
- addToGraph(NewArrayWithSize, get(registerOffset + argumentToOperand(1))));
+ addToGraph(NewArrayWithSize, OpInfo(ArrayWithUndecided), get(registerOffset + argumentToOperand(1))));
return true;
}
@@ -1762,7 +1776,7 @@ bool ByteCodeParser::handleConstantInternalFunction(
addVarArgChild(get(registerOffset + argumentToOperand(i)));
setIntrinsicResult(
usesResult, resultOperand,
- addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0)));
+ addToGraph(Node::VarArg, NewArray, OpInfo(ArrayWithUndecided), OpInfo(0)));
return true;
}
@@ -2122,24 +2136,37 @@ bool ByteCodeParser::parseBlock(unsigned limit)
case op_new_array: {
int startOperand = currentInstruction[2].u.operand;
int numOperands = currentInstruction[3].u.operand;
+ ArrayAllocationProfile* profile = currentInstruction[4].u.arrayAllocationProfile;
for (int operandIdx = startOperand; operandIdx < startOperand + numOperands; ++operandIdx)
addVarArgChild(get(operandIdx));
- set(currentInstruction[1].u.operand, addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0)));
+ set(currentInstruction[1].u.operand, addToGraph(Node::VarArg, NewArray, OpInfo(profile->selectIndexingType()), OpInfo(0)));
NEXT_OPCODE(op_new_array);
}
case op_new_array_with_size: {
int lengthOperand = currentInstruction[2].u.operand;
- set(currentInstruction[1].u.operand, addToGraph(NewArrayWithSize, get(lengthOperand)));
+ ArrayAllocationProfile* profile = currentInstruction[3].u.arrayAllocationProfile;
+ set(currentInstruction[1].u.operand, addToGraph(NewArrayWithSize, OpInfo(profile->selectIndexingType()), get(lengthOperand)));
NEXT_OPCODE(op_new_array_with_size);
}
case op_new_array_buffer: {
int startConstant = currentInstruction[2].u.operand;
int numConstants = currentInstruction[3].u.operand;
+ ArrayAllocationProfile* profile = currentInstruction[4].u.arrayAllocationProfile;
NewArrayBufferData data;
data.startConstant = m_inlineStackTop->m_constantBufferRemap[startConstant];
data.numConstants = numConstants;
+ data.indexingType = profile->selectIndexingType();
+
+ // If this statement has never executed, we'll have the wrong indexing type in the profile.
+ for (int i = 0; i < numConstants; ++i) {
+ data.indexingType =
+ leastUpperBoundOfIndexingTypeAndValue(
+ data.indexingType,
+ m_codeBlock->constantBuffer(data.startConstant)[i]);
+ }
+
m_graph.m_newArrayBufferData.append(data);
set(currentInstruction[1].u.operand, addToGraph(NewArrayBuffer, OpInfo(&m_graph.m_newArrayBufferData.last())));
NEXT_OPCODE(op_new_array_buffer);
diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
index a2570b7ea..308dde5a6 100644
--- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
+++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
@@ -210,6 +210,15 @@ public:
addCallArgument(arg3);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, GPRReg arg3)
+ {
+ resetCallArguments();
+ addCallArgument(GPRInfo::callFrameRegister);
+ addCallArgument(arg1);
+ addCallArgument(arg2);
+ addCallArgument(arg3);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, TrustedImmPtr arg3)
{
resetCallArguments();
@@ -268,6 +277,16 @@ public:
addCallArgument(arg4);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4)
+ {
+ resetCallArguments();
+ addCallArgument(GPRInfo::callFrameRegister);
+ addCallArgument(arg1);
+ addCallArgument(arg2);
+ addCallArgument(arg3);
+ addCallArgument(arg4);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImmPtr arg2, GPRReg arg3)
{
resetCallArguments();
@@ -317,6 +336,23 @@ public:
addCallArgument(arg4);
addCallArgument(arg5);
}
+
+ ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
+ {
+ resetCallArguments();
+ addCallArgument(GPRInfo::callFrameRegister);
+ addCallArgument(arg1);
+ addCallArgument(arg2);
+ }
+
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3)
+ {
+ resetCallArguments();
+ addCallArgument(GPRInfo::callFrameRegister);
+ addCallArgument(arg1);
+ addCallArgument(arg2);
+ addCallArgument(arg3);
+ }
#endif // !NUMBER_OF_ARGUMENT_REGISTERS
// These methods are suitable for any calling convention that provides for
// at least 4 argument registers, e.g. X86_64, ARMv7.
@@ -463,6 +499,20 @@ public:
{
setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2);
}
+
+ ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
+ {
+ moveDouble(arg1, FPRInfo::argumentFPR0);
+ move(arg2, GPRInfo::argumentGPR1);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ }
+
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3)
+ {
+ moveDouble(arg3, FPRInfo::argumentFPR0);
+ setupStubArguments(arg1, arg2);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ }
#elif CPU(ARM)
#if CPU(ARM_HARDFP)
ALWAYS_INLINE void setupArguments(FPRReg arg1)
@@ -496,6 +546,21 @@ public:
assembler().vmov(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, arg1);
assembler().vmov(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, arg2);
}
+
+ ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
+ {
+ move(arg2, GPRInfo::argumentGPR3);
+ assembler().vmov(GPRInfo::argumentGPR1, GPRInfo::argumentGPR2, arg1);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ }
+
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3)
+ {
+ setupStubArguments(arg1, arg2);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ assembler().vmov(GPRInfo::argumentGPR3, GPRInfo::nonArgGPR0, arg3);
+ poke(GPRInfo::nonArgGPR0);
+ }
#endif // CPU(ARM_HARDFP)
#else
#error "DFG JIT not supported on this platform."
@@ -635,6 +700,13 @@ public:
move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, GPRReg arg3)
+ {
+ setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3>(arg1, arg3);
+ move(arg2, GPRInfo::argumentGPR2);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, TrustedImmPtr arg3)
{
move(arg1, GPRInfo::argumentGPR1);
@@ -723,6 +795,12 @@ public:
setupArgumentsWithExecState(arg1, arg2, arg3);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4)
+ {
+ poke(arg4);
+ setupArgumentsWithExecState(arg1, arg2, arg3);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImm32 arg3, GPRReg arg4)
{
poke(arg4);
diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
index e0d973992..e3827d8ad 100644
--- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
@@ -99,9 +99,8 @@ public:
case Branch: {
// Branch on constant -> jettison the not-taken block and merge.
- if (m_graph[m_graph[block->last()].child1()].hasConstant()) {
- bool condition =
- m_graph.valueOfJSConstant(m_graph[block->last()].child1().index()).toBoolean(m_graph.globalObjectFor(m_graph[block->last()].codeOrigin)->globalExec());
+ if (isKnownDirection(block->cfaBranchDirection)) {
+ bool condition = branchCondition(block->cfaBranchDirection);
BasicBlock* targetBlock = m_graph.m_blocks[
m_graph.successorForCondition(block, condition)].get();
if (targetBlock->m_predecessors.size() == 1) {
@@ -730,6 +729,7 @@ private:
}
firstBlock->valuesAtTail = secondBlock->valuesAtTail;
+ firstBlock->cfaBranchDirection = secondBlock->cfaBranchDirection;
m_graph.m_blocks[secondBlockIndex].clear();
}
diff --git a/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h b/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h
index 46d5f44cb..03713b6c5 100644
--- a/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h
+++ b/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h
@@ -61,7 +61,7 @@ protected:
jit->silentSpill(m_plans[i]);
jit->callOperation(m_function, m_resultGPR, m_structure, m_size);
GPRReg canTrample = SpeculativeJIT::pickCanTrample(m_resultGPR);
- for (unsigned i = 0; i < m_plans.size(); ++i)
+ for (unsigned i = m_plans.size(); i--;)
jit->silentFill(m_plans[i], canTrample);
jit->m_jit.loadPtr(MacroAssembler::Address(m_resultGPR, JSObject::butterflyOffset()), m_storageGPR);
jumpTo(jit);
@@ -106,7 +106,7 @@ protected:
done.link(&jit->m_jit);
jit->callOperation(m_function, m_resultGPR, scratchGPR, m_sizeGPR);
GPRReg canTrample = SpeculativeJIT::pickCanTrample(m_resultGPR);
- for (unsigned i = 0; i < m_plans.size(); ++i)
+ for (unsigned i = m_plans.size(); i--;)
jit->silentFill(m_plans[i], canTrample);
jumpTo(jit);
}
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 5a76aa8df..621d6e96a 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -145,7 +145,30 @@ private:
}
case ArrayPush: {
+ // May need to refine the array mode in case the value prediction contravenes
+ // the array prediction. For example, we may have evidence showing that the
+ // array is in Int32 mode, but the value we're storing is likely to be a double.
+ // Then we should turn this into a conversion to Double array followed by the
+ // push. On the other hand, we absolutely don't want to refine based on the
+ // base prediction. If it has non-cell garbage in it, then we want that to be
+ // ignored. That's because ArrayPush can't handle any array modes that aren't
+ // array-related - so if refine() turned this into a "Generic" ArrayPush then
+ // that would break things.
+ node.setArrayMode(
+ node.arrayMode().refine(
+ m_graph[node.child1()].prediction() & SpecCell,
+ SpecInt32,
+ m_graph[node.child2()].prediction()));
blessArrayOperation(node.child1(), node.child2(), 2);
+
+ Node* nodePtr = &m_graph[m_compileIndex];
+ switch (nodePtr->arrayMode().type()) {
+ case Array::Double:
+ fixDoubleEdge(1);
+ break;
+ default:
+ break;
+ }
break;
}
@@ -236,7 +259,7 @@ private:
case ValueAdd: {
if (m_graph.addShouldSpeculateInteger(node))
break;
- if (!Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()]))
+ if (!Node::shouldSpeculateNumberExpectingDefined(m_graph[node.child1()], m_graph[node.child2()]))
break;
fixDoubleEdge(0);
fixDoubleEdge(1);
@@ -262,7 +285,7 @@ private:
case ArithMin:
case ArithMax:
case ArithMod: {
- if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()])
+ if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()])
&& node.canSpeculateInteger())
break;
fixDoubleEdge(0);
@@ -279,7 +302,7 @@ private:
}
case ArithDiv: {
- if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()])
+ if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()])
&& node.canSpeculateInteger()) {
if (isX86())
break;
@@ -307,7 +330,7 @@ private:
}
case ArithAbs: {
- if (m_graph[node.child1()].shouldSpeculateInteger()
+ if (m_graph[node.child1()].shouldSpeculateIntegerForArithmetic()
&& node.canSpeculateInteger())
break;
fixDoubleEdge(0);
@@ -328,13 +351,17 @@ private:
node.setArrayMode(
node.arrayMode().refine(
m_graph[child1].prediction(),
- m_graph[child2].prediction()));
+ m_graph[child2].prediction(),
+ m_graph[child3].prediction()));
blessArrayOperation(child1, child2, 3);
Node* nodePtr = &m_graph[m_compileIndex];
switch (nodePtr->arrayMode().modeForPut().type()) {
+ case Array::Double:
+ fixDoubleEdge(2);
+ break;
case Array::Int8Array:
case Array::Int16Array:
case Array::Int32Array:
@@ -355,6 +382,19 @@ private:
break;
}
+ case NewArray: {
+ for (unsigned i = m_graph.varArgNumChildren(node); i--;) {
+ node.setIndexingType(
+ leastUpperBoundOfIndexingTypeAndType(
+ node.indexingType(), m_graph[m_graph.varArgChild(node, i)].prediction()));
+ }
+ if (node.indexingType() == ArrayWithDouble) {
+ for (unsigned i = m_graph.varArgNumChildren(node); i--;)
+ fixDoubleEdge(i);
+ }
+ break;
+ }
+
default:
break;
}
@@ -392,15 +432,17 @@ private:
if (arrayMode.isJSArrayWithOriginalStructure()) {
JSGlobalObject* globalObject = m_graph.baselineCodeBlockFor(codeOrigin)->globalObject();
switch (arrayMode.type()) {
+ case Array::Int32:
+ structure = globalObject->originalArrayStructureForIndexingType(ArrayWithInt32);
+ break;
+ case Array::Double:
+ structure = globalObject->originalArrayStructureForIndexingType(ArrayWithDouble);
+ break;
case Array::Contiguous:
- structure = globalObject->arrayStructure();
- if (structure->indexingType() != ArrayWithContiguous)
- structure = 0;
+ structure = globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
break;
case Array::ArrayStorage:
- structure = globalObject->arrayStructureWithArrayStorage();
- if (structure->indexingType() != ArrayWithArrayStorage)
- structure = 0;
+ structure = globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage);
break;
default:
break;
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 8e8817f81..38079f020 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -287,6 +287,11 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
dataLog("]");
hasPrinted = true;
}
+ if (node.hasIndexingType()) {
+ if (hasPrinted)
+ dataLog(", ");
+ dataLog("%s", indexingTypeToString(node.indexingType()));
+ }
if (op == JSConstant) {
dataLog("%s$%u", hasPrinted ? ", " : "", node.constantNumber());
JSValue value = valueOfJSConstant(nodeIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 9fbb2df07..4de2e0e26 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -220,7 +220,7 @@ public:
if (right.hasConstant())
return addImmediateShouldSpeculateInteger(add, left, right);
- return Node::shouldSpeculateInteger(left, right) && add.canSpeculateInteger();
+ return Node::shouldSpeculateIntegerExpectingDefined(left, right) && add.canSpeculateInteger();
}
bool mulShouldSpeculateInteger(Node& mul)
@@ -235,13 +235,13 @@ public:
if (right.hasConstant())
return mulImmediateShouldSpeculateInteger(mul, left, right);
- return Node::shouldSpeculateInteger(left, right) && mul.canSpeculateInteger() && !nodeMayOverflow(mul.arithNodeFlags());
+ return Node::shouldSpeculateIntegerForArithmetic(left, right) && mul.canSpeculateInteger() && !nodeMayOverflow(mul.arithNodeFlags());
}
bool negateShouldSpeculateInteger(Node& negate)
{
ASSERT(negate.op() == ArithNegate);
- return at(negate.child1()).shouldSpeculateInteger() && negate.canSpeculateInteger();
+ return at(negate.child1()).shouldSpeculateIntegerForArithmetic() && negate.canSpeculateInteger();
}
bool addShouldSpeculateInteger(NodeIndex nodeIndex)
@@ -493,6 +493,8 @@ public:
switch (node.arrayMode().type()) {
case Array::Generic:
return false;
+ case Array::Int32:
+ case Array::Double:
case Array::Contiguous:
case Array::ArrayStorage:
return !node.arrayMode().isOutOfBounds();
@@ -712,7 +714,7 @@ private:
if (!immediateValue.isNumber())
return false;
- if (!variable.shouldSpeculateInteger())
+ if (!variable.shouldSpeculateIntegerExpectingDefined())
return false;
if (immediateValue.isInt32())
@@ -734,7 +736,7 @@ private:
if (!immediateValue.isInt32())
return false;
- if (!variable.shouldSpeculateInteger())
+ if (!variable.shouldSpeculateIntegerForArithmetic())
return false;
int32_t intImmediate = immediateValue.asInt32();
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index e66629ec4..bff7fe65f 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -62,6 +62,7 @@ struct StructureTransitionData {
struct NewArrayBufferData {
unsigned startConstant;
unsigned numConstants;
+ IndexingType indexingType;
};
// This type used in passing an immediate argument to Node constructor;
@@ -433,6 +434,32 @@ struct Node {
return newArrayBufferData()->numConstants;
}
+ bool hasIndexingType()
+ {
+ switch (op()) {
+ case NewArray:
+ case NewArrayWithSize:
+ case NewArrayBuffer:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ IndexingType indexingType()
+ {
+ ASSERT(hasIndexingType());
+ if (op() == NewArrayBuffer)
+ return newArrayBufferData()->indexingType;
+ return m_opInfo;
+ }
+
+ void setIndexingType(IndexingType indexingType)
+ {
+ ASSERT(hasIndexingType());
+ m_opInfo = indexingType;
+ }
+
bool hasRegexpIndex()
{
return op() == NewRegexp;
@@ -922,16 +949,36 @@ struct Node {
return isInt32Speculation(prediction());
}
+ bool shouldSpeculateIntegerForArithmetic()
+ {
+ return isInt32SpeculationForArithmetic(prediction());
+ }
+
+ bool shouldSpeculateIntegerExpectingDefined()
+ {
+ return isInt32SpeculationExpectingDefined(prediction());
+ }
+
bool shouldSpeculateDouble()
{
return isDoubleSpeculation(prediction());
}
+ bool shouldSpeculateDoubleForArithmetic()
+ {
+ return isDoubleSpeculationForArithmetic(prediction());
+ }
+
bool shouldSpeculateNumber()
{
return isNumberSpeculation(prediction());
}
+ bool shouldSpeculateNumberExpectingDefined()
+ {
+ return isNumberSpeculationExpectingDefined(prediction());
+ }
+
bool shouldSpeculateBoolean()
{
return isBooleanSpeculation(prediction());
@@ -1037,11 +1084,31 @@ struct Node {
return op1.shouldSpeculateInteger() && op2.shouldSpeculateInteger();
}
+ static bool shouldSpeculateIntegerForArithmetic(Node& op1, Node& op2)
+ {
+ return op1.shouldSpeculateIntegerForArithmetic() && op2.shouldSpeculateIntegerForArithmetic();
+ }
+
+ static bool shouldSpeculateIntegerExpectingDefined(Node& op1, Node& op2)
+ {
+ return op1.shouldSpeculateIntegerExpectingDefined() && op2.shouldSpeculateIntegerExpectingDefined();
+ }
+
+ static bool shouldSpeculateDoubleForArithmetic(Node& op1, Node& op2)
+ {
+ return op1.shouldSpeculateDoubleForArithmetic() && op2.shouldSpeculateDoubleForArithmetic();
+ }
+
static bool shouldSpeculateNumber(Node& op1, Node& op2)
{
return op1.shouldSpeculateNumber() && op2.shouldSpeculateNumber();
}
+ static bool shouldSpeculateNumberExpectingDefined(Node& op1, Node& op2)
+ {
+ return op1.shouldSpeculateNumberExpectingDefined() && op2.shouldSpeculateNumberExpectingDefined();
+ }
+
static bool shouldSpeculateFinalObject(Node& op1, Node& op2)
{
return op1.shouldSpeculateFinalObject() && op2.shouldSpeculateFinalObject();
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 0e45e230c..8356d22f9 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -27,9 +27,9 @@
#include "DFGOperations.h"
#include "Arguments.h"
-#include "ButterflyInlineMethods.h"
+#include "ButterflyInlines.h"
#include "CodeBlock.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "DFGOSRExit.h"
#include "DFGRepatch.h"
#include "DFGThunks.h"
@@ -580,6 +580,40 @@ void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec,
array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
}
+void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, double value)
+{
+ JSGlobalData* globalData = &exec->globalData();
+ NativeCallFrameTracer tracer(globalData, exec);
+
+ JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
+
+ if (index >= 0) {
+ array->putByIndexInline(exec, index, jsValue, true);
+ return;
+ }
+
+ PutPropertySlot slot(true);
+ array->methodTable()->put(
+ array, exec, Identifier::from(exec, index), jsValue, slot);
+}
+
+void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, double value)
+{
+ JSGlobalData* globalData = &exec->globalData();
+ NativeCallFrameTracer tracer(globalData, exec);
+
+ JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
+
+ if (index >= 0) {
+ array->putByIndexInline(exec, index, jsValue, false);
+ return;
+ }
+
+ PutPropertySlot slot(false);
+ array->methodTable()->put(
+ array, exec, Identifier::from(exec, index), jsValue, slot);
+}
+
EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
{
JSGlobalData* globalData = &exec->globalData();
@@ -589,6 +623,15 @@ EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue
return JSValue::encode(jsNumber(array->length()));
}
+EncodedJSValue DFG_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array)
+{
+ JSGlobalData* globalData = &exec->globalData();
+ NativeCallFrameTracer tracer(globalData, exec);
+
+ array->push(exec, JSValue(JSValue::EncodeAsDouble, value));
+ return JSValue::encode(jsNumber(array->length()));
+}
+
EncodedJSValue DFG_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
{
JSGlobalData* globalData = &exec->globalData();
@@ -1327,30 +1370,36 @@ char* DFG_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState*
return reinterpret_cast<char*>(result);
}
-char* DFG_OPERATION operationEnsureContiguous(ExecState* exec, JSObject* object)
+char* DFG_OPERATION operationEnsureInt32(ExecState* exec, JSObject* object)
{
JSGlobalData& globalData = exec->globalData();
NativeCallFrameTracer tracer(&globalData, exec);
- return reinterpret_cast<char*>(object->ensureContiguous(globalData));
+ return reinterpret_cast<char*>(object->ensureInt32(globalData));
}
-char* DFG_OPERATION operationEnsureArrayStorage(ExecState* exec, JSObject* object)
+char* DFG_OPERATION operationEnsureDouble(ExecState* exec, JSObject* object)
{
JSGlobalData& globalData = exec->globalData();
NativeCallFrameTracer tracer(&globalData, exec);
+
+ return reinterpret_cast<char*>(object->ensureDouble(globalData));
+}
- return reinterpret_cast<char*>(object->ensureArrayStorage(globalData));
+char* DFG_OPERATION operationEnsureContiguous(ExecState* exec, JSObject* object)
+{
+ JSGlobalData& globalData = exec->globalData();
+ NativeCallFrameTracer tracer(&globalData, exec);
+
+ return reinterpret_cast<char*>(object->ensureContiguous(globalData));
}
-char* DFG_OPERATION operationEnsureContiguousOrArrayStorage(ExecState* exec, JSObject* object, int32_t index)
+char* DFG_OPERATION operationEnsureArrayStorage(ExecState* exec, JSObject* object)
{
JSGlobalData& globalData = exec->globalData();
NativeCallFrameTracer tracer(&globalData, exec);
- if (static_cast<unsigned>(index) >= MIN_SPARSE_ARRAY_INDEX)
- return reinterpret_cast<char*>(object->ensureArrayStorage(globalData));
- return reinterpret_cast<char*>(object->ensureIndexedStorage(globalData));
+ return reinterpret_cast<char*>(object->ensureArrayStorage(globalData));
}
double DFG_OPERATION operationFModOnInts(int32_t a, int32_t b)
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 8d2beacec..b99c214e9 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -64,6 +64,7 @@ typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EAZ)(ExecState*, JSArray*,
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECI)(ExecState*, JSCell*, Identifier*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EDA)(ExecState*, double, JSArray*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EGriJsgI)(ExecState*, ResolveOperation*, JSGlobalObject*, Identifier*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EI)(ExecState*, Identifier*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EIRo)(ExecState*, Identifier*, ResolveOperations*);
@@ -92,6 +93,7 @@ typedef size_t DFG_OPERATION (*S_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*)
typedef size_t DFG_OPERATION (*S_DFGOperation_EJ)(ExecState*, EncodedJSValue);
typedef size_t DFG_OPERATION (*S_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
typedef size_t DFG_OPERATION (*S_DFGOperation_J)(EncodedJSValue);
+typedef void DFG_OPERATION (*V_DFGOperation_EOZD)(ExecState*, JSObject*, int32_t, double);
typedef void DFG_OPERATION (*V_DFGOperation_EOZJ)(ExecState*, JSObject*, int32_t, EncodedJSValue);
typedef void DFG_OPERATION (*V_DFGOperation_EC)(ExecState*, JSCell*);
typedef void DFG_OPERATION (*V_DFGOperation_ECIcf)(ExecState*, JSCell*, InlineCallFrame*);
@@ -148,7 +150,10 @@ void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSVal
void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
+void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
+void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationArrayPushDouble(ExecState*, double value, JSArray*) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationArrayPopAndRecoverLength(ExecState*, JSArray*) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState*, JSCell*, JSCell*) WTF_INTERNAL;
@@ -195,9 +200,10 @@ char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecStat
char* DFG_OPERATION operationAllocatePropertyStorage(ExecState*, size_t newSize) WTF_INTERNAL;
char* DFG_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState*, JSObject*) WTF_INTERNAL;
char* DFG_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState*, JSObject*, size_t newSize) WTF_INTERNAL;
+char* DFG_OPERATION operationEnsureInt32(ExecState*, JSObject*);
+char* DFG_OPERATION operationEnsureDouble(ExecState*, JSObject*);
char* DFG_OPERATION operationEnsureContiguous(ExecState*, JSObject*);
char* DFG_OPERATION operationEnsureArrayStorage(ExecState*, JSObject*);
-char* DFG_OPERATION operationEnsureContiguousOrArrayStorage(ExecState*, JSObject*, int32_t);
// This method is used to lookup an exception hander, keyed by faultLocation, which is
// the return location from one of the calls out to one of the helper operations above.
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 3e8ead5c6..b5fde4eee 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -225,24 +225,6 @@ private:
break;
}
- case ArithMod: {
- SpeculatedType left = m_graph[node.child1()].prediction();
- SpeculatedType right = m_graph[node.child2()].prediction();
-
- if (left && right) {
- if (isInt32Speculation(mergeSpeculations(left, right))
- && nodeCanSpeculateInteger(node.arithNodeFlags()))
- changed |= mergePrediction(SpecInt32);
- else
- changed |= mergePrediction(SpecDouble);
- }
-
- flags |= NodeUsedAsValue;
- changed |= m_graph[node.child1()].mergeFlags(flags);
- changed |= m_graph[node.child2()].mergeFlags(flags);
- break;
- }
-
case UInt32ToNumber: {
if (nodeCanSpeculateInteger(node.arithNodeFlags()))
changed |= mergePrediction(SpecInt32);
@@ -258,7 +240,7 @@ private:
SpeculatedType right = m_graph[node.child2()].prediction();
if (left && right) {
- if (isNumberSpeculation(left) && isNumberSpeculation(right)) {
+ if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)) {
if (m_graph.addShouldSpeculateInteger(node))
changed |= mergePrediction(SpecInt32);
else
@@ -333,7 +315,7 @@ private:
SpeculatedType right = m_graph[node.child2()].prediction();
if (left && right) {
- if (isInt32Speculation(mergeSpeculations(left, right))
+ if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()])
&& nodeCanSpeculateInteger(node.arithNodeFlags()))
changed |= mergePrediction(SpecInt32);
else
@@ -373,7 +355,7 @@ private:
SpeculatedType right = m_graph[node.child2()].prediction();
if (left && right) {
- if (isInt32Speculation(mergeSpeculations(left, right))
+ if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()])
&& nodeCanSpeculateInteger(node.arithNodeFlags()))
changed |= mergePrediction(SpecInt32);
else
@@ -382,7 +364,7 @@ private:
// As soon as a multiply happens, we can easily end up in the part
// of the double domain where the point at which you do truncation
- // can change the outcome. So, ArithMul always checks for overflow
+ // can change the outcome. So, ArithDiv always checks for overflow
// no matter what, and always forces its inputs to check as well.
flags |= NodeUsedAsNumber | NodeNeedsNegZero;
@@ -391,6 +373,24 @@ private:
break;
}
+ case ArithMod: {
+ SpeculatedType left = m_graph[node.child1()].prediction();
+ SpeculatedType right = m_graph[node.child2()].prediction();
+
+ if (left && right) {
+ if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()])
+ && nodeCanSpeculateInteger(node.arithNodeFlags()))
+ changed |= mergePrediction(SpecInt32);
+ else
+ changed |= mergePrediction(SpecDouble);
+ }
+
+ flags |= NodeUsedAsValue;
+ changed |= m_graph[node.child1()].mergeFlags(flags);
+ changed |= m_graph[node.child2()].mergeFlags(flags);
+ break;
+ }
+
case ArithSqrt: {
changed |= setPrediction(SpecDouble);
changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue);
@@ -399,10 +399,11 @@ private:
case ArithAbs: {
SpeculatedType child = m_graph[node.child1()].prediction();
- if (nodeCanSpeculateInteger(node.arithNodeFlags()))
- changed |= mergePrediction(child);
+ if (isInt32SpeculationForArithmetic(child)
+ && nodeCanSpeculateInteger(node.arithNodeFlags()))
+ changed |= mergePrediction(SpecInt32);
else
- changed |= setPrediction(speculatedDoubleTypeForPrediction(child));
+ changed |= mergePrediction(speculatedDoubleTypeForPrediction(child));
flags &= ~NodeNeedsNegZero;
changed |= m_graph[node.child1()].mergeFlags(flags);
@@ -776,7 +777,7 @@ private:
DoubleBallot ballot;
- if (isNumberSpeculation(left) && isNumberSpeculation(right)
+ if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)
&& !m_graph.addShouldSpeculateInteger(node))
ballot = VoteDouble;
else
@@ -814,7 +815,7 @@ private:
DoubleBallot ballot;
if (isNumberSpeculation(left) && isNumberSpeculation(right)
- && !(Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child1()])
+ && !(Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child1()])
&& node.canSpeculateInteger()))
ballot = VoteDouble;
else
@@ -827,7 +828,7 @@ private:
case ArithAbs:
DoubleBallot ballot;
- if (!(m_graph[node.child1()].shouldSpeculateInteger()
+ if (!(m_graph[node.child1()].shouldSpeculateIntegerForArithmetic()
&& node.canSpeculateInteger()))
ballot = VoteDouble;
else
@@ -849,6 +850,24 @@ private:
break;
}
+ case PutByVal:
+ case PutByValAlias: {
+ Edge child1 = m_graph.varArgChild(node, 0);
+ Edge child2 = m_graph.varArgChild(node, 1);
+ Edge child3 = m_graph.varArgChild(node, 2);
+ m_graph.vote(child1, VoteValue);
+ m_graph.vote(child2, VoteValue);
+ switch (node.arrayMode().type()) {
+ case Array::Double:
+ m_graph.vote(child3, VoteDouble);
+ break;
+ default:
+ m_graph.vote(child3, VoteValue);
+ break;
+ }
+ break;
+ }
+
default:
m_graph.vote(node, VoteValue);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 6bedd6d68..829bc14ff 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -59,7 +59,7 @@ SpeculativeJIT::~SpeculativeJIT()
void SpeculativeJIT::emitAllocateJSArray(Structure* structure, GPRReg resultGPR, GPRReg storageGPR, unsigned numElements)
{
- ASSERT(hasContiguous(structure->indexingType()));
+ ASSERT(hasUndecided(structure->indexingType()) || hasInt32(structure->indexingType()) || hasDouble(structure->indexingType()) || hasContiguous(structure->indexingType()));
GPRTemporary scratch(this);
GPRReg scratchGPR = scratch.gpr();
@@ -67,6 +67,7 @@ void SpeculativeJIT::emitAllocateJSArray(Structure* structure, GPRReg resultGPR,
unsigned vectorLength = std::max(BASE_VECTOR_LEN, numElements);
JITCompiler::JumpList slowCases;
+
slowCases.append(
emitAllocateBasicStorage(TrustedImm32(vectorLength * sizeof(JSValue) + sizeof(IndexingHeader)), storageGPR));
m_jit.subPtr(TrustedImm32(vectorLength * sizeof(JSValue)), storageGPR);
@@ -79,6 +80,21 @@ void SpeculativeJIT::emitAllocateJSArray(Structure* structure, GPRReg resultGPR,
m_jit.store32(TrustedImm32(numElements), MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
m_jit.store32(TrustedImm32(vectorLength), MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
+ if (hasDouble(structure->indexingType()) && numElements < vectorLength) {
+#if USE(JSVALUE64)
+ m_jit.move(TrustedImm64(bitwise_cast<int64_t>(QNaN)), scratchGPR);
+ for (unsigned i = numElements; i < vectorLength; ++i)
+ m_jit.store64(scratchGPR, MacroAssembler::Address(storageGPR, sizeof(double) * i));
+#else
+ EncodedValueDescriptor value;
+ value.asInt64 = JSValue::encode(JSValue(JSValue::EncodeAsDouble, QNaN));
+ for (unsigned i = numElements; i < vectorLength; ++i) {
+ m_jit.store32(TrustedImm32(value.asBits.tag), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ m_jit.store32(TrustedImm32(value.asBits.payload), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+ }
+#endif
+ }
+
// I want a slow path that also loads out the storage pointer, and that's
// what this custom CallArrayAllocatorSlowPathGenerator gives me. It's a lot
// of work for a very small piece of functionality. :-/
@@ -343,24 +359,31 @@ const TypedArrayDescriptor* SpeculativeJIT::typedArrayDescriptor(ArrayMode array
}
}
+JITCompiler::Jump SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode, IndexingType shape, bool invert)
+{
+ if (arrayMode.isJSArray()) {
+ m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR);
+ return m_jit.branch32(
+ invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | shape));
+ }
+ m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
+ return m_jit.branch32(invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape));
+}
+
JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode, bool invert)
{
JITCompiler::JumpList result;
switch (arrayMode.type()) {
- case Array::Contiguous: {
- if (arrayMode.isJSArray()) {
- m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR);
- result.append(
- m_jit.branch32(
- invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | ContiguousShape)));
- break;
- }
- m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
- result.append(
- m_jit.branch32(invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(ContiguousShape)));
- break;
- }
+ case Array::Int32:
+ return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, Int32Shape, invert);
+
+ case Array::Double:
+ return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, DoubleShape, invert);
+
+ case Array::Contiguous:
+ return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, ContiguousShape, invert);
+
case Array::ArrayStorage:
case Array::SlowPutArrayStorage: {
if (arrayMode.isJSArray()) {
@@ -437,6 +460,8 @@ void SpeculativeJIT::checkArray(Node& node)
case Array::String:
expectedClassInfo = &JSString::s_info;
break;
+ case Array::Int32:
+ case Array::Double:
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage: {
@@ -528,16 +553,30 @@ void SpeculativeJIT::arrayify(Node& node, GPRReg baseReg, GPRReg propertyReg)
// If we're allegedly creating contiguous storage and the index is bogus, then
// just don't.
- if (node.arrayMode().type() == Array::Contiguous && propertyReg != InvalidGPRReg) {
- speculationCheck(
- Uncountable, JSValueRegs(), NoNode,
- m_jit.branch32(
- MacroAssembler::AboveOrEqual, propertyReg, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)));
+ if (propertyReg != InvalidGPRReg) {
+ switch (node.arrayMode().type()) {
+ case Array::Int32:
+ case Array::Double:
+ case Array::Contiguous:
+ speculationCheck(
+ Uncountable, JSValueRegs(), NoNode,
+ m_jit.branch32(
+ MacroAssembler::AboveOrEqual, propertyReg, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)));
+ break;
+ default:
+ break;
+ }
}
// Now call out to create the array storage.
silentSpillAllRegisters(tempGPR);
switch (node.arrayMode().type()) {
+ case Array::Int32:
+ callOperation(operationEnsureInt32, tempGPR, baseReg);
+ break;
+ case Array::Double:
+ callOperation(operationEnsureDouble, tempGPR, baseReg);
+ break;
case Array::Contiguous:
callOperation(operationEnsureContiguous, tempGPR, baseReg);
break;
@@ -1797,6 +1836,85 @@ ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSo
return ValueRecovery();
}
+void SpeculativeJIT::compileDoublePutByVal(Node& node, SpeculateCellOperand& base, SpeculateStrictInt32Operand& property)
+{
+ Edge child3 = m_jit.graph().varArgChild(node, 2);
+ Edge child4 = m_jit.graph().varArgChild(node, 3);
+
+ ArrayMode arrayMode = node.arrayMode();
+
+ GPRReg baseReg = base.gpr();
+ GPRReg propertyReg = property.gpr();
+
+ SpeculateDoubleOperand value(this, child3);
+
+ FPRReg valueReg = value.fpr();
+
+ if (!isRealNumberSpeculation(m_state.forNode(child3).m_type)) {
+ // FIXME: We need a way of profiling these, and we need to hoist them into
+ // SpeculateDoubleOperand.
+ speculationCheck(
+ BadType, JSValueRegs(), NoNode,
+ m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueReg, valueReg));
+ }
+
+ if (!m_compileOkay)
+ return;
+
+ StorageOperand storage(this, child4);
+ GPRReg storageReg = storage.gpr();
+
+ if (node.op() == PutByValAlias) {
+ // Store the value to the array.
+ GPRReg propertyReg = property.gpr();
+ FPRReg valueReg = value.fpr();
+ m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight));
+
+ noResult(m_compileIndex);
+ return;
+ }
+
+ GPRTemporary temporary;
+ GPRReg temporaryReg = temporaryRegisterForPutByVal(temporary, node);
+
+ MacroAssembler::JumpList slowCases;
+
+ if (arrayMode.isInBounds()) {
+ speculationCheck(
+ Uncountable, JSValueRegs(), NoNode,
+ m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
+ } else {
+ MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
+
+ slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength())));
+
+ if (!arrayMode.isOutOfBounds())
+ speculationCheck(Uncountable, JSValueRegs(), NoNode, slowCases);
+
+ m_jit.add32(TrustedImm32(1), propertyReg, temporaryReg);
+ m_jit.store32(temporaryReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
+
+ inBounds.link(&m_jit);
+ }
+
+ m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight));
+
+ base.use();
+ property.use();
+ value.use();
+ storage.use();
+
+ if (arrayMode.isOutOfBounds()) {
+ addSlowPathGenerator(
+ slowPathCall(
+ slowCases, this,
+ m_jit.codeBlock()->isStrictMode() ? operationPutDoubleByValBeyondArrayBoundsStrict : operationPutDoubleByValBeyondArrayBoundsNonStrict,
+ NoResult, baseReg, propertyReg, valueReg));
+ }
+
+ noResult(m_compileIndex, UseChildrenCalledExplicitly);
+}
+
void SpeculativeJIT::compileGetCharCodeAt(Node& node)
{
SpeculateCellOperand string(this, node.child1());
@@ -2763,7 +2881,7 @@ void SpeculativeJIT::compileAdd(Node& node)
return;
}
- if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
+ if (Node::shouldSpeculateNumberExpectingDefined(at(node.child1()), at(node.child2()))) {
SpeculateDoubleOperand op1(this, node.child1());
SpeculateDoubleOperand op2(this, node.child2());
FPRTemporary result(this, op1, op2);
@@ -3001,7 +3119,7 @@ void SpeculativeJIT::compileIntegerArithDivForX86(Node& node)
void SpeculativeJIT::compileArithMod(Node& node)
{
- if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2()))
+ if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2()))
&& node.canSpeculateInteger()) {
compileSoftModulo(node);
return;
@@ -3336,6 +3454,8 @@ void SpeculativeJIT::compileGetArrayLength(Node& node)
const TypedArrayDescriptor* descriptor = typedArrayDescriptor(node.arrayMode());
switch (node.arrayMode().type()) {
+ case Array::Int32:
+ case Array::Double:
case Array::Contiguous: {
StorageOperand storage(this, node.child2());
GPRTemporary result(this, storage);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 446ea7dbe..059d3a6c6 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1308,6 +1308,11 @@ public:
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(J_DFGOperation_EDA operation, GPRReg result, FPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1, arg2);
@@ -1453,6 +1458,11 @@ public:
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
return appendCallWithExceptionCheck(operation);
}
+ JITCompiler::Call callOperation(V_DFGOperation_EOZD operation, GPRReg arg1, GPRReg arg2, FPRReg arg3)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+ return appendCallWithExceptionCheck(operation);
+ }
JITCompiler::Call callOperation(V_DFGOperation_EOZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
@@ -1661,11 +1671,21 @@ public:
m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, TrustedImm32(arg1Tag), TrustedImmPtr(identifier));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(J_DFGOperation_EDA operation, GPRReg resultTag, GPRReg resultPayload, FPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg resultTag, GPRReg resultPayload, TrustedImm32 arg1Tag, GPRReg arg1Payload, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
JITCompiler::Call callOperation(J_DFGOperation_EJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload)
{
m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag);
@@ -1819,11 +1839,21 @@ public:
m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
return appendCallWithExceptionCheck(operation);
}
+ JITCompiler::Call callOperation(V_DFGOperation_EOZD operation, GPRReg arg1, GPRReg arg2, FPRReg arg3)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+ return appendCallWithExceptionCheck(operation);
+ }
JITCompiler::Call callOperation(V_DFGOperation_EOZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3Tag, GPRReg arg3Payload)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
return appendCallWithExceptionCheck(operation);
}
+ JITCompiler::Call callOperation(V_DFGOperation_EOZJ operation, GPRReg arg1, GPRReg arg2, TrustedImm32 arg3Tag, GPRReg arg3Payload)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
+ return appendCallWithExceptionCheck(operation);
+ }
JITCompiler::Call callOperation(V_DFGOperation_W operation, WatchpointSet* watchpointSet)
{
m_jit.setupArguments(TrustedImmPtr(watchpointSet));
@@ -2270,6 +2300,11 @@ public:
void compileAllocatePropertyStorage(Node&);
void compileReallocatePropertyStorage(Node&);
+#if USE(JSVALUE32_64)
+ template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType>
+ void compileContiguousPutByVal(Node&, BaseOperandType&, PropertyOperandType&, ValueOperandType&, GPRReg valuePayloadReg, TagType valueTag);
+#endif
+ void compileDoublePutByVal(Node&, SpeculateCellOperand& base, SpeculateStrictInt32Operand& property);
bool putByValWillNeedExtraRegister(ArrayMode arrayMode)
{
return arrayMode.mayStoreToHole();
@@ -2415,6 +2450,7 @@ public:
const TypedArrayDescriptor* typedArrayDescriptor(ArrayMode);
+ JITCompiler::Jump jumpSlowForUnwantedArrayMode(GPRReg tempWithIndexingTypeReg, ArrayMode, IndexingType, bool invert);
JITCompiler::JumpList jumpSlowForUnwantedArrayMode(GPRReg tempWithIndexingTypeReg, ArrayMode, bool invert = false);
void checkArray(Node&);
void arrayify(Node&, GPRReg baseReg, GPRReg propertyReg);
@@ -2955,6 +2991,11 @@ public:
m_gprOrInvalid = m_jit->fillSpeculateInt(index(), m_format);
return m_gprOrInvalid;
}
+
+ void use()
+ {
+ m_jit->use(m_index);
+ }
private:
SpeculativeJIT* m_jit;
@@ -3035,6 +3076,11 @@ public:
m_fprOrInvalid = m_jit->fillSpeculateDouble(index());
return m_fprOrInvalid;
}
+
+ void use()
+ {
+ m_jit->use(m_index);
+ }
private:
SpeculativeJIT* m_jit;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 65fdf5593..694f1452e 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2046,6 +2046,69 @@ void SpeculativeJIT::emitBranch(Node& node)
}
}
+template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType>
+void SpeculativeJIT::compileContiguousPutByVal(Node& node, BaseOperandType& base, PropertyOperandType& property, ValueOperandType& value, GPRReg valuePayloadReg, TagType valueTag)
+{
+ Edge child4 = m_jit.graph().varArgChild(node, 3);
+
+ ArrayMode arrayMode = node.arrayMode();
+
+ GPRReg baseReg = base.gpr();
+ GPRReg propertyReg = property.gpr();
+
+ StorageOperand storage(this, child4);
+ GPRReg storageReg = storage.gpr();
+
+ if (node.op() == PutByValAlias) {
+ // Store the value to the array.
+ GPRReg propertyReg = property.gpr();
+ m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+
+ noResult(m_compileIndex);
+ return;
+ }
+
+ MacroAssembler::JumpList slowCases;
+
+ if (arrayMode.isInBounds()) {
+ speculationCheck(
+ Uncountable, JSValueRegs(), NoNode,
+ m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
+ } else {
+ MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
+
+ slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength())));
+
+ if (!arrayMode.isOutOfBounds())
+ speculationCheck(Uncountable, JSValueRegs(), NoNode, slowCases);
+
+ m_jit.add32(TrustedImm32(1), propertyReg);
+ m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
+ m_jit.sub32(TrustedImm32(1), propertyReg);
+
+ inBounds.link(&m_jit);
+ }
+
+ m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+
+ base.use();
+ property.use();
+ value.use();
+ storage.use();
+
+ if (arrayMode.isOutOfBounds()) {
+ addSlowPathGenerator(
+ slowPathCall(
+ slowCases, this,
+ m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
+ NoResult, baseReg, propertyReg, valueTag, valuePayloadReg));
+ }
+
+ noResult(m_compileIndex, UseChildrenCalledExplicitly);
+}
+
void SpeculativeJIT::compile(Node& node)
{
NodeType op = node.op();
@@ -2366,7 +2429,8 @@ void SpeculativeJIT::compile(Node& node)
break;
case ArithDiv: {
- if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
+ if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2()))
+ && node.canSpeculateInteger()) {
#if CPU(X86)
compileIntegerArithDivForX86(node);
#else // CPU(X86) -> so non-X86 code follows
@@ -2393,7 +2457,8 @@ void SpeculativeJIT::compile(Node& node)
}
case ArithAbs: {
- if (at(node.child1()).shouldSpeculateInteger() && node.canSpeculateInteger()) {
+ if (at(node.child1()).shouldSpeculateIntegerForArithmetic()
+ && node.canSpeculateInteger()) {
SpeculateIntegerOperand op1(this, node.child1());
GPRTemporary result(this, op1);
GPRTemporary scratch(this);
@@ -2417,7 +2482,8 @@ void SpeculativeJIT::compile(Node& node)
case ArithMin:
case ArithMax: {
- if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
+ if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2()))
+ && node.canSpeculateInteger()) {
SpeculateStrictInt32Operand op1(this, node.child1());
SpeculateStrictInt32Operand op2(this, node.child2());
GPRTemporary result(this, op1);
@@ -2567,6 +2633,7 @@ void SpeculativeJIT::compile(Node& node)
jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
break;
}
+ case Array::Int32:
case Array::Contiguous: {
if (node.arrayMode().isInBounds()) {
SpeculateStrictInt32Operand property(this, node.child2());
@@ -2580,8 +2647,20 @@ void SpeculativeJIT::compile(Node& node)
speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
- GPRTemporary resultTag(this);
GPRTemporary resultPayload(this);
+ if (node.arrayMode().type() == Array::Int32) {
+ speculationCheck(
+ OutOfBounds, JSValueRegs(), NoNode,
+ m_jit.branch32(
+ MacroAssembler::Equal,
+ MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)),
+ TrustedImm32(JSValue::EmptyValueTag)));
+ m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
+ integerResult(resultPayload.gpr(), m_compileIndex);
+ break;
+ }
+
+ GPRTemporary resultTag(this);
m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
@@ -2621,6 +2700,60 @@ void SpeculativeJIT::compile(Node& node)
jsValueResult(resultTagReg, resultPayloadReg, m_compileIndex);
break;
}
+ case Array::Double: {
+ if (node.arrayMode().isInBounds()) {
+ SpeculateStrictInt32Operand property(this, node.child2());
+ StorageOperand storage(this, node.child3());
+
+ GPRReg propertyReg = property.gpr();
+ GPRReg storageReg = storage.gpr();
+
+ if (!m_compileOkay)
+ return;
+
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
+
+ FPRTemporary result(this);
+ m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ SpeculateCellOperand base(this, node.child1());
+ SpeculateStrictInt32Operand property(this, node.child2());
+ StorageOperand storage(this, node.child3());
+
+ GPRReg baseReg = base.gpr();
+ GPRReg propertyReg = property.gpr();
+ GPRReg storageReg = storage.gpr();
+
+ if (!m_compileOkay)
+ return;
+
+ GPRTemporary resultTag(this);
+ GPRTemporary resultPayload(this);
+ FPRTemporary temp(this);
+ GPRReg resultTagReg = resultTag.gpr();
+ GPRReg resultPayloadReg = resultPayload.gpr();
+ FPRReg tempReg = temp.fpr();
+
+ MacroAssembler::JumpList slowCases;
+
+ slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
+
+ m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
+ slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempReg, tempReg));
+ boxDouble(tempReg, resultTagReg, resultPayloadReg);
+
+ addSlowPathGenerator(
+ slowPathCall(
+ slowCases, this, operationGetByValArrayInt,
+ JSValueRegs(resultTagReg, resultPayloadReg), baseReg, propertyReg));
+
+ jsValueResult(resultTagReg, resultPayloadReg, m_compileIndex);
+ break;
+ }
case Array::ArrayStorage:
case Array::SlowPutArrayStorage: {
if (node.arrayMode().isInBounds()) {
@@ -2771,6 +2904,17 @@ void SpeculativeJIT::compile(Node& node)
GPRReg propertyReg = property.gpr();
switch (arrayMode.type()) {
+ case Array::Int32: {
+ SpeculateIntegerOperand value(this, child3);
+
+ GPRReg valuePayloadReg = value.gpr();
+
+ if (!m_compileOkay)
+ return;
+
+ compileContiguousPutByVal(node, base, property, value, valuePayloadReg, TrustedImm32(JSValue::Int32Tag));
+ break;
+ }
case Array::Contiguous: {
JSValueOperand value(this, child3);
@@ -2784,61 +2928,14 @@ void SpeculativeJIT::compile(Node& node)
GPRTemporary scratch(this);
writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratch.gpr());
}
-
- StorageOperand storage(this, child4);
- GPRReg storageReg = storage.gpr();
-
- if (node.op() == PutByValAlias) {
- // Store the value to the array.
- GPRReg propertyReg = property.gpr();
- m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
- m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
-
- noResult(m_compileIndex);
- break;
- }
-
- MacroAssembler::JumpList slowCases;
-
- if (arrayMode.isInBounds()) {
- speculationCheck(
- Uncountable, JSValueRegs(), NoNode,
- m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
- } else {
- MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
-
- slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength())));
-
- if (!arrayMode.isOutOfBounds())
- speculationCheck(Uncountable, JSValueRegs(), NoNode, slowCases);
-
- m_jit.add32(TrustedImm32(1), propertyReg);
- m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
- m_jit.sub32(TrustedImm32(1), propertyReg);
-
- inBounds.link(&m_jit);
- }
-
- m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
- m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
-
- base.use();
- property.use();
- value.use();
- storage.use();
- if (arrayMode.isOutOfBounds()) {
- addSlowPathGenerator(
- slowPathCall(
- slowCases, this,
- m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
- NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
- }
-
- noResult(m_compileIndex, UseChildrenCalledExplicitly);
+ compileContiguousPutByVal(node, base, property, value, valuePayloadReg, valueTagReg);
+ break;
+ }
+ case Array::Double: {
+ compileDoublePutByVal(node, base, property);
break;
}
-
case Array::ArrayStorage:
case Array::SlowPutArrayStorage: {
JSValueOperand value(this, child3);
@@ -3028,24 +3125,47 @@ void SpeculativeJIT::compile(Node& node)
ASSERT(node.arrayMode().isJSArray());
SpeculateCellOperand base(this, node.child1());
- JSValueOperand value(this, node.child2());
GPRTemporary storageLength(this);
GPRReg baseGPR = base.gpr();
- GPRReg valueTagGPR = value.tagGPR();
- GPRReg valuePayloadGPR = value.payloadGPR();
GPRReg storageLengthGPR = storageLength.gpr();
- if (Heap::isWriteBarrierEnabled()) {
- GPRTemporary scratch(this);
- writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
- }
-
StorageOperand storage(this, node.child3());
GPRReg storageGPR = storage.gpr();
switch (node.arrayMode().type()) {
+ case Array::Int32: {
+ SpeculateIntegerOperand value(this, node.child2());
+ GPRReg valuePayloadGPR = value.gpr();
+
+ m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
+ MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
+ m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+ m_jit.add32(TrustedImm32(1), storageLengthGPR);
+ m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
+ m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
+
+ addSlowPathGenerator(
+ slowPathCall(
+ slowPath, this, operationArrayPush,
+ JSValueRegs(storageGPR, storageLengthGPR),
+ TrustedImm32(JSValue::Int32Tag), valuePayloadGPR, baseGPR));
+
+ jsValueResult(storageGPR, storageLengthGPR, m_compileIndex);
+ break;
+ }
+
case Array::Contiguous: {
+ JSValueOperand value(this, node.child2());
+ GPRReg valueTagGPR = value.tagGPR();
+ GPRReg valuePayloadGPR = value.payloadGPR();
+
+ if (Heap::isWriteBarrierEnabled()) {
+ GPRTemporary scratch(this);
+ writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
+ }
+
m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
@@ -3064,7 +3184,45 @@ void SpeculativeJIT::compile(Node& node)
break;
}
+ case Array::Double: {
+ SpeculateDoubleOperand value(this, node.child2());
+ FPRReg valueFPR = value.fpr();
+
+ if (!isRealNumberSpeculation(m_state.forNode(node.child2()).m_type)) {
+ // FIXME: We need a way of profiling these, and we need to hoist them into
+ // SpeculateDoubleOperand.
+ speculationCheck(
+ BadType, JSValueRegs(), NoNode,
+ m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
+ }
+
+ m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
+ MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
+ m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
+ m_jit.add32(TrustedImm32(1), storageLengthGPR);
+ m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
+ m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
+
+ addSlowPathGenerator(
+ slowPathCall(
+ slowPath, this, operationArrayPushDouble,
+ JSValueRegs(storageGPR, storageLengthGPR),
+ valueFPR, baseGPR));
+
+ jsValueResult(storageGPR, storageLengthGPR, m_compileIndex);
+ break;
+ }
+
case Array::ArrayStorage: {
+ JSValueOperand value(this, node.child2());
+ GPRReg valueTagGPR = value.tagGPR();
+ GPRReg valuePayloadGPR = value.payloadGPR();
+
+ if (Heap::isWriteBarrierEnabled()) {
+ GPRTemporary scratch(this);
+ writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
+ }
+
m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
// Refuse to handle bizarre lengths.
@@ -3107,6 +3265,7 @@ void SpeculativeJIT::compile(Node& node)
GPRReg storageGPR = storage.gpr();
switch (node.arrayMode().type()) {
+ case Array::Int32:
case Array::Contiguous: {
m_jit.load32(
MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR);
@@ -3140,6 +3299,44 @@ void SpeculativeJIT::compile(Node& node)
break;
}
+ case Array::Double: {
+ FPRTemporary temp(this);
+ FPRReg tempFPR = temp.fpr();
+
+ m_jit.load32(
+ MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR);
+ MacroAssembler::Jump undefinedCase =
+ m_jit.branchTest32(MacroAssembler::Zero, valuePayloadGPR);
+ m_jit.sub32(TrustedImm32(1), valuePayloadGPR);
+ m_jit.store32(
+ valuePayloadGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
+ m_jit.loadDouble(
+ MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight),
+ tempFPR);
+ MacroAssembler::Jump slowCase = m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempFPR, tempFPR);
+ JSValue nan = JSValue(JSValue::EncodeAsDouble, QNaN);
+ m_jit.store32(
+ MacroAssembler::TrustedImm32(nan.u.asBits.tag),
+ MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ m_jit.store32(
+ MacroAssembler::TrustedImm32(nan.u.asBits.payload),
+ MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+ boxDouble(tempFPR, valueTagGPR, valuePayloadGPR);
+
+ addSlowPathGenerator(
+ slowPathMove(
+ undefinedCase, this,
+ MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR,
+ MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR));
+ addSlowPathGenerator(
+ slowPathCall(
+ slowCase, this, operationArrayPopAndRecoverLength,
+ JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
+
+ jsValueResult(valueTagGPR, valuePayloadGPR, m_compileIndex);
+ break;
+ }
+
case Array::ArrayStorage: {
GPRTemporary storageLength(this);
GPRReg storageLengthGPR = storageLength.gpr();
@@ -3358,11 +3555,17 @@ void SpeculativeJIT::compile(Node& node)
case NewArray: {
JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
- if (!globalObject->isHavingABadTime()) {
+ if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) {
globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
- ASSERT(hasContiguous(globalObject->arrayStructure()->indexingType()));
-
+ Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType());
+ ASSERT(structure->indexingType() == node.indexingType());
+ ASSERT(
+ hasUndecided(structure->indexingType())
+ || hasInt32(structure->indexingType())
+ || hasDouble(structure->indexingType())
+ || hasContiguous(structure->indexingType()));
+
unsigned numElements = node.numChildren();
GPRTemporary result(this);
@@ -3371,17 +3574,52 @@ void SpeculativeJIT::compile(Node& node)
GPRReg resultGPR = result.gpr();
GPRReg storageGPR = storage.gpr();
- emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements);
+ emitAllocateJSArray(structure, resultGPR, storageGPR, numElements);
// At this point, one way or another, resultGPR and storageGPR have pointers to
// the JSArray and the Butterfly, respectively.
+ ASSERT(!hasUndecided(structure->indexingType()) || !node.numChildren());
+
for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
- JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
- GPRReg opTagGPR = operand.tagGPR();
- GPRReg opPayloadGPR = operand.payloadGPR();
- m_jit.store32(opTagGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
- m_jit.store32(opPayloadGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+ Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx];
+ switch (node.indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ CRASH();
+ break;
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ SpeculateDoubleOperand operand(this, use);
+ FPRReg opFPR = operand.fpr();
+ if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
+ // FIXME: We need a way of profiling these, and we need to hoist them into
+ // SpeculateDoubleOperand.
+ speculationCheck(
+ BadType, JSValueRegs(), NoNode,
+ m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
+ }
+
+ m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
+ break;
+ }
+ case ALL_INT32_INDEXING_TYPES: {
+ SpeculateIntegerOperand operand(this, use);
+ m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ m_jit.store32(operand.gpr(), MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+ break;
+ }
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
+ GPRReg opTagGPR = operand.tagGPR();
+ GPRReg opPayloadGPR = operand.payloadGPR();
+ m_jit.store32(opTagGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ m_jit.store32(opPayloadGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+ break;
+ }
+ default:
+ CRASH();
+ break;
+ }
}
// Yuck, we should *really* have a way of also returning the storageGPR. But
@@ -3399,7 +3637,7 @@ void SpeculativeJIT::compile(Node& node)
flushRegisters();
GPRResult result(this);
callOperation(
- operationNewEmptyArray, result.gpr(), globalObject->arrayStructure());
+ operationNewEmptyArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()));
cellResult(result.gpr(), m_compileIndex);
break;
}
@@ -3409,13 +3647,61 @@ void SpeculativeJIT::compile(Node& node)
EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
- JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
- GPRReg opTagGPR = operand.tagGPR();
- GPRReg opPayloadGPR = operand.payloadGPR();
- operand.use();
-
- m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
- m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+ // Need to perform the speculations that this node promises to perform. If we're
+ // emitting code here and the indexing type is not array storage then there is
+ // probably something hilarious going on and we're already failing at all the
+ // things, but at least we're going to be sound.
+ Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx];
+ switch (node.indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ CRASH();
+ break;
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ SpeculateDoubleOperand operand(this, use);
+ FPRReg opFPR = operand.fpr();
+ if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
+ // FIXME: We need a way of profiling these, and we need to hoist them into
+ // SpeculateDoubleOperand.
+ speculationCheck(
+ BadType, JSValueRegs(), NoNode,
+ m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
+ }
+
+ m_jit.storeDouble(opFPR, reinterpret_cast<char*>(buffer + operandIdx));
+ break;
+ }
+ case ALL_INT32_INDEXING_TYPES: {
+ SpeculateIntegerOperand operand(this, use);
+ GPRReg opGPR = operand.gpr();
+ m_jit.store32(TrustedImm32(JSValue::Int32Tag), reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+ m_jit.store32(opGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+ break;
+ }
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
+ JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
+ GPRReg opTagGPR = operand.tagGPR();
+ GPRReg opPayloadGPR = operand.payloadGPR();
+
+ m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+ m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+ operand.use();
+ break;
+ }
+ default:
+ CRASH();
+ break;
+ }
+ }
+
+ switch (node.indexingType()) {
+ case ALL_DOUBLE_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ useChildren(node);
+ break;
+ default:
+ break;
}
flushRegisters();
@@ -3431,8 +3717,8 @@ void SpeculativeJIT::compile(Node& node)
GPRResult result(this);
callOperation(
- operationNewArray, result.gpr(), globalObject->arrayStructure(),
- static_cast<void *>(buffer), node.numChildren());
+ operationNewArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()),
+ static_cast<void*>(buffer), node.numChildren());
if (scratchSize) {
GPRTemporary scratch(this);
@@ -3471,17 +3757,30 @@ void SpeculativeJIT::compile(Node& node)
emitAllocateBasicStorage(resultGPR, storageGPR));
m_jit.subPtr(scratchGPR, storageGPR);
emitAllocateBasicJSObject<JSArray, MarkedBlock::None>(
- TrustedImmPtr(globalObject->arrayStructure()), resultGPR, scratchGPR,
+ TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), resultGPR, scratchGPR,
storageGPR, sizeof(JSArray), slowCases);
m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
+ if (hasDouble(node.indexingType())) {
+ JSValue nan = JSValue(JSValue::EncodeAsDouble, QNaN);
+
+ m_jit.move(sizeGPR, scratchGPR);
+ MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
+ MacroAssembler::Label loop = m_jit.label();
+ m_jit.sub32(TrustedImm32(1), scratchGPR);
+ m_jit.store32(TrustedImm32(nan.u.asBits.tag), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ m_jit.store32(TrustedImm32(nan.u.asBits.payload), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+ m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
+ done.link(&m_jit);
+ }
+
addSlowPathGenerator(adoptPtr(
new CallArrayAllocatorWithVariableSizeSlowPathGenerator(
slowCases, this, operationNewArrayWithSize, resultGPR,
- globalObject->arrayStructure(),
- globalObject->arrayStructureWithArrayStorage(),
+ globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()),
+ globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage),
sizeGPR)));
cellResult(resultGPR, m_compileIndex);
@@ -3492,15 +3791,24 @@ void SpeculativeJIT::compile(Node& node)
GPRReg sizeGPR = size.gpr();
flushRegisters();
GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+ GPRReg structureGPR = selectScratchGPR(sizeGPR);
+ MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX));
+ m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), structureGPR);
+ MacroAssembler::Jump done = m_jit.jump();
+ bigLength.link(&m_jit);
+ m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)), structureGPR);
+ done.link(&m_jit);
callOperation(
- operationNewArrayWithSize, result.gpr(), globalObject->arrayStructure(), sizeGPR);
- cellResult(result.gpr(), m_compileIndex);
+ operationNewArrayWithSize, resultGPR, structureGPR, sizeGPR);
+ cellResult(resultGPR, m_compileIndex);
break;
}
case NewArrayBuffer: {
JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
- if (!globalObject->isHavingABadTime()) {
+ IndexingType indexingType = node.indexingType();
+ if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) {
globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
unsigned numElements = node.numConstants();
@@ -3511,12 +3819,25 @@ void SpeculativeJIT::compile(Node& node)
GPRReg resultGPR = result.gpr();
GPRReg storageGPR = storage.gpr();
- emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements);
+ emitAllocateJSArray(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), resultGPR, storageGPR, numElements);
- int32_t* data = bitwise_cast<int32_t*>(m_jit.codeBlock()->constantBuffer(node.startConstant()));
- for (unsigned index = 0; index < node.numConstants() * 2; ++index) {
- m_jit.store32(
- Imm32(data[index]), MacroAssembler::Address(storageGPR, sizeof(int32_t) * index));
+ if (node.indexingType() == ArrayWithDouble) {
+ JSValue* data = m_jit.codeBlock()->constantBuffer(node.startConstant());
+ for (unsigned index = 0; index < node.numConstants(); ++index) {
+ union {
+ int32_t halves[2];
+ double value;
+ } u;
+ u.value = data[index].asNumber();
+ m_jit.store32(Imm32(u.halves[0]), MacroAssembler::Address(storageGPR, sizeof(double) * index));
+ m_jit.store32(Imm32(u.halves[1]), MacroAssembler::Address(storageGPR, sizeof(double) * index + sizeof(int32_t)));
+ }
+ } else {
+ int32_t* data = bitwise_cast<int32_t*>(m_jit.codeBlock()->constantBuffer(node.startConstant()));
+ for (unsigned index = 0; index < node.numConstants() * 2; ++index) {
+ m_jit.store32(
+ Imm32(data[index]), MacroAssembler::Address(storageGPR, sizeof(int32_t) * index));
+ }
}
cellResult(resultGPR, m_compileIndex);
@@ -3526,7 +3847,7 @@ void SpeculativeJIT::compile(Node& node)
flushRegisters();
GPRResult result(this);
- callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructure(), node.startConstant(), node.numConstants());
+ callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), node.startConstant(), node.numConstants());
cellResult(result.gpr(), m_compileIndex);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 6c066c388..ecd823e7b 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2403,7 +2403,8 @@ void SpeculativeJIT::compile(Node& node)
break;
case ArithDiv: {
- if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
+ if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2()))
+ && node.canSpeculateInteger()) {
compileIntegerArithDivForX86(node);
break;
}
@@ -2426,7 +2427,8 @@ void SpeculativeJIT::compile(Node& node)
}
case ArithAbs: {
- if (at(node.child1()).shouldSpeculateInteger() && node.canSpeculateInteger()) {
+ if (at(node.child1()).shouldSpeculateIntegerForArithmetic()
+ && node.canSpeculateInteger()) {
SpeculateIntegerOperand op1(this, node.child1());
GPRTemporary result(this);
GPRTemporary scratch(this);
@@ -2450,7 +2452,8 @@ void SpeculativeJIT::compile(Node& node)
case ArithMin:
case ArithMax: {
- if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
+ if (Node::shouldSpeculateIntegerForArithmetic(at(node.child1()), at(node.child2()))
+ && node.canSpeculateInteger()) {
SpeculateStrictInt32Operand op1(this, node.child1());
SpeculateStrictInt32Operand op2(this, node.child2());
GPRTemporary result(this, op1);
@@ -2598,6 +2601,7 @@ void SpeculativeJIT::compile(Node& node)
jsValueResult(result.gpr(), m_compileIndex);
break;
}
+ case Array::Int32:
case Array::Contiguous: {
if (node.arrayMode().isInBounds()) {
SpeculateStrictInt32Operand property(this, node.child2());
@@ -2614,7 +2618,7 @@ void SpeculativeJIT::compile(Node& node)
GPRTemporary result(this);
m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.gpr());
speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchTest64(MacroAssembler::Zero, result.gpr()));
- jsValueResult(result.gpr(), m_compileIndex);
+ jsValueResult(result.gpr(), m_compileIndex, node.arrayMode().type() == Array::Int32 ? DataFormatJSInteger : DataFormatJS);
break;
}
@@ -2647,6 +2651,60 @@ void SpeculativeJIT::compile(Node& node)
jsValueResult(resultReg, m_compileIndex);
break;
}
+
+ case Array::Double: {
+ if (node.arrayMode().isInBounds()) {
+ SpeculateStrictInt32Operand property(this, node.child2());
+ StorageOperand storage(this, node.child3());
+
+ GPRReg propertyReg = property.gpr();
+ GPRReg storageReg = storage.gpr();
+
+ if (!m_compileOkay)
+ return;
+
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
+
+ FPRTemporary result(this);
+ m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ SpeculateCellOperand base(this, node.child1());
+ SpeculateStrictInt32Operand property(this, node.child2());
+ StorageOperand storage(this, node.child3());
+
+ GPRReg baseReg = base.gpr();
+ GPRReg propertyReg = property.gpr();
+ GPRReg storageReg = storage.gpr();
+
+ if (!m_compileOkay)
+ return;
+
+ GPRTemporary result(this);
+ FPRTemporary temp(this);
+ GPRReg resultReg = result.gpr();
+ FPRReg tempReg = temp.fpr();
+
+ MacroAssembler::JumpList slowCases;
+
+ slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
+
+ m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
+ slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempReg, tempReg));
+ boxDouble(tempReg, resultReg);
+
+ addSlowPathGenerator(
+ slowPathCall(
+ slowCases, this, operationGetByValArrayInt,
+ result.gpr(), baseReg, propertyReg));
+
+ jsValueResult(resultReg, m_compileIndex);
+ break;
+ }
+
case Array::ArrayStorage:
case Array::SlowPutArrayStorage: {
if (node.arrayMode().isInBounds()) {
@@ -2789,6 +2847,7 @@ void SpeculativeJIT::compile(Node& node)
GPRReg propertyReg = property.gpr();
switch (arrayMode.type()) {
+ case Array::Int32:
case Array::Contiguous: {
JSValueOperand value(this, child3);
@@ -2796,8 +2855,15 @@ void SpeculativeJIT::compile(Node& node)
if (!m_compileOkay)
return;
+
+ if (arrayMode.type() == Array::Int32
+ && !isInt32Speculation(m_state.forNode(child3).m_type)) {
+ speculationCheck(
+ BadType, JSValueRegs(valueReg), child3,
+ m_jit.branch64(MacroAssembler::Below, valueReg, GPRInfo::tagTypeNumberRegister));
+ }
- if (Heap::isWriteBarrierEnabled()) {
+ if (arrayMode.type() == Array::Contiguous && Heap::isWriteBarrierEnabled()) {
GPRTemporary scratch(this);
writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratch.gpr());
}
@@ -2857,6 +2923,11 @@ void SpeculativeJIT::compile(Node& node)
break;
}
+ case Array::Double: {
+ compileDoublePutByVal(node, base, property);
+ break;
+ }
+
case Array::ArrayStorage:
case Array::SlowPutArrayStorage: {
JSValueOperand value(this, child3);
@@ -3081,23 +3152,31 @@ void SpeculativeJIT::compile(Node& node)
ASSERT(node.arrayMode().isJSArray());
SpeculateCellOperand base(this, node.child1());
- JSValueOperand value(this, node.child2());
GPRTemporary storageLength(this);
GPRReg baseGPR = base.gpr();
- GPRReg valueGPR = value.gpr();
GPRReg storageLengthGPR = storageLength.gpr();
- if (Heap::isWriteBarrierEnabled()) {
- GPRTemporary scratch(this);
- writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
- }
-
StorageOperand storage(this, node.child3());
GPRReg storageGPR = storage.gpr();
switch (node.arrayMode().type()) {
+ case Array::Int32:
case Array::Contiguous: {
+ JSValueOperand value(this, node.child2());
+ GPRReg valueGPR = value.gpr();
+
+ if (node.arrayMode().type() == Array::Int32 && !isInt32Speculation(m_state.forNode(node.child2()).m_type)) {
+ speculationCheck(
+ BadType, JSValueRegs(valueGPR), node.child2(),
+ m_jit.branch64(MacroAssembler::Below, valueGPR, GPRInfo::tagTypeNumberRegister));
+ }
+
+ if (node.arrayMode().type() != Array::Int32 && Heap::isWriteBarrierEnabled()) {
+ GPRTemporary scratch(this);
+ writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
+ }
+
m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
m_jit.store64(valueGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
@@ -3114,7 +3193,43 @@ void SpeculativeJIT::compile(Node& node)
break;
}
+ case Array::Double: {
+ SpeculateDoubleOperand value(this, node.child2());
+ FPRReg valueFPR = value.fpr();
+
+ if (!isRealNumberSpeculation(m_state.forNode(node.child2()).m_type)) {
+ // FIXME: We need a way of profiling these, and we need to hoist them into
+ // SpeculateDoubleOperand.
+ speculationCheck(
+ BadType, JSValueRegs(), NoNode,
+ m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
+ }
+
+ m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
+ MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
+ m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
+ m_jit.add32(TrustedImm32(1), storageLengthGPR);
+ m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
+ m_jit.or64(GPRInfo::tagTypeNumberRegister, storageLengthGPR);
+
+ addSlowPathGenerator(
+ slowPathCall(
+ slowPath, this, operationArrayPushDouble, NoResult, storageLengthGPR,
+ valueFPR, baseGPR));
+
+ jsValueResult(storageLengthGPR, m_compileIndex);
+ break;
+ }
+
case Array::ArrayStorage: {
+ JSValueOperand value(this, node.child2());
+ GPRReg valueGPR = value.gpr();
+
+ if (Heap::isWriteBarrierEnabled()) {
+ GPRTemporary scratch(this);
+ writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
+ }
+
m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
// Refuse to handle bizarre lengths.
@@ -3152,13 +3267,17 @@ void SpeculativeJIT::compile(Node& node)
StorageOperand storage(this, node.child2());
GPRTemporary value(this);
GPRTemporary storageLength(this);
+ FPRTemporary temp(this); // This is kind of lame, since we don't always need it. I'm relying on the fact that we don't have FPR pressure, especially in code that uses pop().
GPRReg baseGPR = base.gpr();
GPRReg storageGPR = storage.gpr();
GPRReg valueGPR = value.gpr();
GPRReg storageLengthGPR = storageLength.gpr();
+ FPRReg tempFPR = temp.fpr();
switch (node.arrayMode().type()) {
+ case Array::Int32:
+ case Array::Double:
case Array::Contiguous: {
m_jit.load32(
MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
@@ -3167,14 +3286,27 @@ void SpeculativeJIT::compile(Node& node)
m_jit.sub32(TrustedImm32(1), storageLengthGPR);
m_jit.store32(
storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
- m_jit.load64(
- MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight),
- valueGPR);
- // FIXME: This would not have to be here if changing the publicLength also zeroed the values between the old
- // length and the new length.
- m_jit.store64(
+ MacroAssembler::Jump slowCase;
+ if (node.arrayMode().type() == Array::Double) {
+ m_jit.loadDouble(
+ MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight),
+ tempFPR);
+ // FIXME: This would not have to be here if changing the publicLength also zeroed the values between the old
+ // length and the new length.
+ m_jit.store64(
+ MacroAssembler::TrustedImm64((int64_t)0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
+ slowCase = m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempFPR, tempFPR);
+ boxDouble(tempFPR, valueGPR);
+ } else {
+ m_jit.load64(
+ MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight),
+ valueGPR);
+ // FIXME: This would not have to be here if changing the publicLength also zeroed the values between the old
+ // length and the new length.
+ m_jit.store64(
MacroAssembler::TrustedImm64((int64_t)0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
- MacroAssembler::Jump slowCase = m_jit.branchTest64(MacroAssembler::Zero, valueGPR);
+ slowCase = m_jit.branchTest64(MacroAssembler::Zero, valueGPR);
+ }
addSlowPathGenerator(
slowPathMove(
@@ -3184,6 +3316,7 @@ void SpeculativeJIT::compile(Node& node)
slowPathCall(
slowCase, this, operationArrayPopAndRecoverLength, valueGPR, baseGPR));
+ // We can't know for sure that the result is an int because of the slow paths. :-/
jsValueResult(valueGPR, m_compileIndex);
break;
}
@@ -3338,10 +3471,16 @@ void SpeculativeJIT::compile(Node& node)
case NewArray: {
JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
- if (!globalObject->isHavingABadTime()) {
+ if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) {
globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
- ASSERT(hasContiguous(globalObject->arrayStructure()->indexingType()));
+ Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType());
+ ASSERT(structure->indexingType() == node.indexingType());
+ ASSERT(
+ hasUndecided(structure->indexingType())
+ || hasInt32(structure->indexingType())
+ || hasDouble(structure->indexingType())
+ || hasContiguous(structure->indexingType()));
unsigned numElements = node.numChildren();
@@ -3351,15 +3490,50 @@ void SpeculativeJIT::compile(Node& node)
GPRReg resultGPR = result.gpr();
GPRReg storageGPR = storage.gpr();
- emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements);
+ emitAllocateJSArray(structure, resultGPR, storageGPR, numElements);
// At this point, one way or another, resultGPR and storageGPR have pointers to
// the JSArray and the Butterfly, respectively.
+ ASSERT(!hasUndecided(structure->indexingType()) || !node.numChildren());
+
for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
- JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
- GPRReg opGPR = operand.gpr();
- m_jit.store64(opGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx));
+ Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx];
+ switch (node.indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ CRASH();
+ break;
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ SpeculateDoubleOperand operand(this, use);
+ FPRReg opFPR = operand.fpr();
+ if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
+ // FIXME: We need a way of profiling these, and we need to hoist them into
+ // SpeculateDoubleOperand.
+ speculationCheck(
+ BadType, JSValueRegs(), NoNode,
+ m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
+ }
+
+ m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
+ break;
+ }
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ JSValueOperand operand(this, use);
+ GPRReg opGPR = operand.gpr();
+ if (hasInt32(node.indexingType()) && !isInt32Speculation(m_state.forNode(use).m_type)) {
+ speculationCheck(
+ BadType, JSValueRegs(opGPR), use.index(),
+ m_jit.branch64(MacroAssembler::Below, opGPR, GPRInfo::tagTypeNumberRegister));
+ }
+ m_jit.store64(opGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx));
+ break;
+ }
+ default:
+ CRASH();
+ break;
+ }
}
// Yuck, we should *really* have a way of also returning the storageGPR. But
@@ -3376,7 +3550,7 @@ void SpeculativeJIT::compile(Node& node)
if (!node.numChildren()) {
flushRegisters();
GPRResult result(this);
- callOperation(operationNewEmptyArray, result.gpr(), globalObject->arrayStructure());
+ callOperation(operationNewEmptyArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()));
cellResult(result.gpr(), m_compileIndex);
break;
}
@@ -3386,11 +3560,65 @@ void SpeculativeJIT::compile(Node& node)
EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
- JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
- GPRReg opGPR = operand.gpr();
- operand.use();
-
- m_jit.store64(opGPR, buffer + operandIdx);
+ // Need to perform the speculations that this node promises to perform. If we're
+ // emitting code here and the indexing type is not array storage then there is
+ // probably something hilarious going on and we're already failing at all the
+ // things, but at least we're going to be sound.
+ Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx];
+ switch (node.indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ CRASH();
+ break;
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ SpeculateDoubleOperand operand(this, use);
+ GPRTemporary scratch(this);
+ FPRReg opFPR = operand.fpr();
+ GPRReg scratchGPR = scratch.gpr();
+ if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
+ // FIXME: We need a way of profiling these, and we need to hoist them into
+ // SpeculateDoubleOperand.
+ speculationCheck(
+ BadType, JSValueRegs(), NoNode,
+ m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
+ }
+
+ m_jit.boxDouble(opFPR, scratchGPR);
+ m_jit.store64(scratchGPR, buffer + operandIdx);
+ break;
+ }
+ case ALL_INT32_INDEXING_TYPES: {
+ JSValueOperand operand(this, use);
+ GPRReg opGPR = operand.gpr();
+ if (hasInt32(node.indexingType()) && !isInt32Speculation(m_state.forNode(use).m_type)) {
+ speculationCheck(
+ BadType, JSValueRegs(opGPR), use.index(),
+ m_jit.branch64(MacroAssembler::Below, opGPR, GPRInfo::tagTypeNumberRegister));
+ }
+ m_jit.store64(opGPR, buffer + operandIdx);
+ break;
+ }
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
+ JSValueOperand operand(this, use);
+ GPRReg opGPR = operand.gpr();
+ m_jit.store64(opGPR, buffer + operandIdx);
+ operand.use();
+ break;
+ }
+ default:
+ CRASH();
+ break;
+ }
+ }
+
+ switch (node.indexingType()) {
+ case ALL_DOUBLE_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ useChildren(node);
+ break;
+ default:
+ break;
}
flushRegisters();
@@ -3406,7 +3634,7 @@ void SpeculativeJIT::compile(Node& node)
GPRResult result(this);
callOperation(
- operationNewArray, result.gpr(), globalObject->arrayStructure(),
+ operationNewArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()),
static_cast<void*>(buffer), node.numChildren());
if (scratchSize) {
@@ -3422,18 +3650,26 @@ void SpeculativeJIT::compile(Node& node)
case NewArrayWithSize: {
JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
- if (!globalObject->isHavingABadTime()) {
+ if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) {
globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
SpeculateStrictInt32Operand size(this, node.child1());
GPRTemporary result(this);
GPRTemporary storage(this);
GPRTemporary scratch(this);
+ GPRTemporary scratch2;
GPRReg sizeGPR = size.gpr();
GPRReg resultGPR = result.gpr();
GPRReg storageGPR = storage.gpr();
GPRReg scratchGPR = scratch.gpr();
+ GPRReg scratch2GPR = InvalidGPRReg;
+
+ if (hasDouble(node.indexingType())) {
+ GPRTemporary realScratch2(this, size);
+ scratch2.adopt(realScratch2);
+ scratch2GPR = scratch2.gpr();
+ }
MacroAssembler::JumpList slowCases;
slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)));
@@ -3446,17 +3682,28 @@ void SpeculativeJIT::compile(Node& node)
emitAllocateBasicStorage(resultGPR, storageGPR));
m_jit.subPtr(scratchGPR, storageGPR);
emitAllocateBasicJSObject<JSArray, MarkedBlock::None>(
- TrustedImmPtr(globalObject->arrayStructure()), resultGPR, scratchGPR,
+ TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), resultGPR, scratchGPR,
storageGPR, sizeof(JSArray), slowCases);
m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
+ if (hasDouble(node.indexingType())) {
+ m_jit.move(TrustedImm64(bitwise_cast<int64_t>(QNaN)), scratchGPR);
+ m_jit.move(sizeGPR, scratch2GPR);
+ MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratch2GPR);
+ MacroAssembler::Label loop = m_jit.label();
+ m_jit.sub32(TrustedImm32(1), scratch2GPR);
+ m_jit.store64(scratchGPR, MacroAssembler::BaseIndex(storageGPR, scratch2GPR, MacroAssembler::TimesEight));
+ m_jit.branchTest32(MacroAssembler::NonZero, scratch2GPR).linkTo(loop, &m_jit);
+ done.link(&m_jit);
+ }
+
addSlowPathGenerator(adoptPtr(
new CallArrayAllocatorWithVariableSizeSlowPathGenerator(
slowCases, this, operationNewArrayWithSize, resultGPR,
- globalObject->arrayStructure(),
- globalObject->arrayStructureWithArrayStorage(),
+ globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()),
+ globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage),
sizeGPR)));
cellResult(resultGPR, m_compileIndex);
@@ -3470,10 +3717,10 @@ void SpeculativeJIT::compile(Node& node)
GPRReg resultGPR = result.gpr();
GPRReg structureGPR = selectScratchGPR(sizeGPR);
MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX));
- m_jit.move(TrustedImmPtr(globalObject->arrayStructure()), structureGPR);
+ m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), structureGPR);
MacroAssembler::Jump done = m_jit.jump();
bigLength.link(&m_jit);
- m_jit.move(TrustedImmPtr(globalObject->arrayStructureWithArrayStorage()), structureGPR);
+ m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)), structureGPR);
done.link(&m_jit);
callOperation(operationNewArrayWithSize, resultGPR, structureGPR, sizeGPR);
cellResult(resultGPR, m_compileIndex);
@@ -3520,7 +3767,8 @@ void SpeculativeJIT::compile(Node& node)
case NewArrayBuffer: {
JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
- if (!globalObject->isHavingABadTime()) {
+ IndexingType indexingType = node.indexingType();
+ if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) {
globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
unsigned numElements = node.numConstants();
@@ -3531,13 +3779,23 @@ void SpeculativeJIT::compile(Node& node)
GPRReg resultGPR = result.gpr();
GPRReg storageGPR = storage.gpr();
- emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements);
+ emitAllocateJSArray(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), resultGPR, storageGPR, numElements);
+ ASSERT(indexingType & IsArray);
JSValue* data = m_jit.codeBlock()->constantBuffer(node.startConstant());
- for (unsigned index = 0; index < node.numConstants(); ++index) {
- m_jit.store64(
- Imm64(JSValue::encode(data[index])),
- MacroAssembler::Address(storageGPR, sizeof(JSValue) * index));
+ if (indexingType == ArrayWithDouble) {
+ for (unsigned index = 0; index < node.numConstants(); ++index) {
+ double value = data[index].asNumber();
+ m_jit.store64(
+ Imm64(bitwise_cast<int64_t>(value)),
+ MacroAssembler::Address(storageGPR, sizeof(double) * index));
+ }
+ } else {
+ for (unsigned index = 0; index < node.numConstants(); ++index) {
+ m_jit.store64(
+ Imm64(JSValue::encode(data[index])),
+ MacroAssembler::Address(storageGPR, sizeof(JSValue) * index));
+ }
}
cellResult(resultGPR, m_compileIndex);
@@ -3547,7 +3805,7 @@ void SpeculativeJIT::compile(Node& node)
flushRegisters();
GPRResult result(this);
- callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructure(), node.startConstant(), node.numConstants());
+ callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), node.startConstant(), node.numConstants());
cellResult(result.gpr(), m_compileIndex);
break;
diff --git a/Source/JavaScriptCore/heap/BlockAllocator.cpp b/Source/JavaScriptCore/heap/BlockAllocator.cpp
index 16f607396..daba93805 100644
--- a/Source/JavaScriptCore/heap/BlockAllocator.cpp
+++ b/Source/JavaScriptCore/heap/BlockAllocator.cpp
@@ -28,6 +28,7 @@
#include "CopiedBlock.h"
#include "MarkedBlock.h"
+#include "WeakBlock.h"
#include <wtf/CurrentTime.h>
namespace JSC {
@@ -35,6 +36,7 @@ namespace JSC {
BlockAllocator::BlockAllocator()
: m_copiedRegionSet(CopiedBlock::blockSize)
, m_markedRegionSet(MarkedBlock::blockSize)
+ , m_weakRegionSet(WeakBlock::blockSize)
, m_numberOfEmptyRegions(0)
, m_isCurrentlyAllocating(false)
, m_blockFreeingThreadShouldQuit(false)
diff --git a/Source/JavaScriptCore/heap/BlockAllocator.h b/Source/JavaScriptCore/heap/BlockAllocator.h
index a41df1aab..f8ce39530 100644
--- a/Source/JavaScriptCore/heap/BlockAllocator.h
+++ b/Source/JavaScriptCore/heap/BlockAllocator.h
@@ -39,6 +39,7 @@ class BlockAllocator;
class CopiedBlock;
class MarkedBlock;
class Region;
+class WeakBlock;
// Simple allocator to reduce VM cost by holding onto blocks of memory for
// short periods of time and then freeing them on a secondary thread.
@@ -184,6 +185,7 @@ private:
RegionSet m_copiedRegionSet;
RegionSet m_markedRegionSet;
+ RegionSet m_weakRegionSet;
DoublyLinkedList<Region> m_emptyRegions;
size_t m_numberOfEmptyRegions;
@@ -311,6 +313,12 @@ inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<MarkedBlock>()
}
template <>
+inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<WeakBlock>()
+{
+ return m_weakRegionSet;
+}
+
+template <>
inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<CopiedBlock> >()
{
return m_copiedRegionSet;
@@ -322,6 +330,12 @@ inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<MarkedB
return m_markedRegionSet;
}
+template <>
+inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<WeakBlock> >()
+{
+ return m_weakRegionSet;
+}
+
template <typename T>
inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor()
{
diff --git a/Source/JavaScriptCore/heap/ConservativeRoots.cpp b/Source/JavaScriptCore/heap/ConservativeRoots.cpp
index 7fe22dfff..752ce2775 100644
--- a/Source/JavaScriptCore/heap/ConservativeRoots.cpp
+++ b/Source/JavaScriptCore/heap/ConservativeRoots.cpp
@@ -26,9 +26,9 @@
#include "config.h"
#include "ConservativeRoots.h"
-#include "CopiedSpace.h"
-#include "CopiedSpaceInlineMethods.h"
#include "CodeBlock.h"
+#include "CopiedSpace.h"
+#include "CopiedSpaceInlines.h"
#include "DFGCodeBlocks.h"
#include "JSCell.h"
#include "JSObject.h"
diff --git a/Source/JavaScriptCore/heap/CopiedBlock.h b/Source/JavaScriptCore/heap/CopiedBlock.h
index af36f55df..83fdb08da 100644
--- a/Source/JavaScriptCore/heap/CopiedBlock.h
+++ b/Source/JavaScriptCore/heap/CopiedBlock.h
@@ -29,7 +29,7 @@
#include "BlockAllocator.h"
#include "HeapBlock.h"
#include "JSValue.h"
-#include "JSValueInlineMethods.h"
+#include "JSValueInlines.h"
#include "Options.h"
#include <wtf/Atomics.h>
diff --git a/Source/JavaScriptCore/heap/CopiedSpace.cpp b/Source/JavaScriptCore/heap/CopiedSpace.cpp
index c228f9460..e4141c1d7 100644
--- a/Source/JavaScriptCore/heap/CopiedSpace.cpp
+++ b/Source/JavaScriptCore/heap/CopiedSpace.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "CopiedSpace.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "GCActivityCallback.h"
#include "Options.h"
diff --git a/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h b/Source/JavaScriptCore/heap/CopiedSpaceInlines.h
index c244015e7..9d222f549 100644
--- a/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h
+++ b/Source/JavaScriptCore/heap/CopiedSpaceInlines.h
@@ -23,8 +23,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CopiedSpaceInlineMethods_h
-#define CopiedSpaceInlineMethods_h
+#ifndef CopiedSpaceInlines_h
+#define CopiedSpaceInlines_h
#include "CopiedBlock.h"
#include "CopiedSpace.h"
@@ -182,4 +182,5 @@ inline CopiedBlock* CopiedSpace::blockFor(void* ptr)
} // namespace JSC
-#endif
+#endif // CopiedSpaceInlines_h
+
diff --git a/Source/JavaScriptCore/heap/CopyVisitor.cpp b/Source/JavaScriptCore/heap/CopyVisitor.cpp
index ae826f0d2..22ab57882 100644
--- a/Source/JavaScriptCore/heap/CopyVisitor.cpp
+++ b/Source/JavaScriptCore/heap/CopyVisitor.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "CopyVisitor.h"
-#include "CopyVisitorInlineMethods.h"
+#include "CopyVisitorInlines.h"
#include "GCThreadSharedData.h"
#include "JSCell.h"
#include "JSObject.h"
diff --git a/Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h b/Source/JavaScriptCore/heap/CopyVisitorInlines.h
index eb7bd2e82..bd7879429 100644
--- a/Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h
+++ b/Source/JavaScriptCore/heap/CopyVisitorInlines.h
@@ -23,8 +23,8 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CopyVisitorInlineMethods_h
-#define CopyVisitorInlineMethods_h
+#ifndef CopyVisitorInlines_h
+#define CopyVisitorInlines_h
#include "ClassInfo.h"
#include "CopyVisitor.h"
@@ -116,4 +116,5 @@ inline void CopyVisitor::didCopy(void* ptr, size_t bytes)
} // namespace JSC
-#endif
+#endif // CopyVisitorInlines_h
+
diff --git a/Source/JavaScriptCore/heap/GCThread.cpp b/Source/JavaScriptCore/heap/GCThread.cpp
index ce3bbedc9..7caa7d588 100644
--- a/Source/JavaScriptCore/heap/GCThread.cpp
+++ b/Source/JavaScriptCore/heap/GCThread.cpp
@@ -27,7 +27,7 @@
#include "GCThread.h"
#include "CopyVisitor.h"
-#include "CopyVisitorInlineMethods.h"
+#include "CopyVisitorInlines.h"
#include "GCThreadSharedData.h"
#include "SlotVisitor.h"
#include <wtf/MainThread.h>
diff --git a/Source/JavaScriptCore/heap/GCThreadSharedData.cpp b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp
index 446b41c2f..cf12d4bcd 100644
--- a/Source/JavaScriptCore/heap/GCThreadSharedData.cpp
+++ b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp
@@ -27,12 +27,12 @@
#include "GCThreadSharedData.h"
#include "CopyVisitor.h"
-#include "CopyVisitorInlineMethods.h"
+#include "CopyVisitorInlines.h"
#include "GCThread.h"
#include "JSGlobalData.h"
#include "MarkStack.h"
#include "SlotVisitor.h"
-#include "SlotVisitorInlineMethods.h"
+#include "SlotVisitorInlines.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/heap/HandleStack.cpp b/Source/JavaScriptCore/heap/HandleStack.cpp
index 42eb326a5..a5653c748 100644
--- a/Source/JavaScriptCore/heap/HandleStack.cpp
+++ b/Source/JavaScriptCore/heap/HandleStack.cpp
@@ -27,8 +27,8 @@
#include "HandleStack.h"
#include "HeapRootVisitor.h"
-#include "JSValueInlineMethods.h"
#include "JSObject.h"
+#include "JSValueInlines.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index c455fc2b1..0fb65e205 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -24,8 +24,8 @@
#include "CodeBlock.h"
#include "ConservativeRoots.h"
#include "CopiedSpace.h"
-#include "CopiedSpaceInlineMethods.h"
-#include "CopyVisitorInlineMethods.h"
+#include "CopiedSpaceInlines.h"
+#include "CopyVisitorInlines.h"
#include "GCActivityCallback.h"
#include "HeapRootVisitor.h"
#include "HeapStatistics.h"
diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h
index 51cebdc0e..d0d03959b 100644
--- a/Source/JavaScriptCore/heap/Heap.h
+++ b/Source/JavaScriptCore/heap/Heap.h
@@ -188,6 +188,7 @@ namespace JSC {
friend class SlotVisitor;
friend class IncrementalSweeper;
friend class HeapStatistics;
+ friend class WeakSet;
template<typename T> friend void* allocateCell(Heap&);
template<typename T> friend void* allocateCell(Heap&, size_t);
diff --git a/Source/JavaScriptCore/heap/HeapRootVisitor.h b/Source/JavaScriptCore/heap/HeapRootVisitor.h
index 9849d7c39..5b11a5ead 100644
--- a/Source/JavaScriptCore/heap/HeapRootVisitor.h
+++ b/Source/JavaScriptCore/heap/HeapRootVisitor.h
@@ -27,7 +27,7 @@
#define HeapRootVisitor_h
#include "SlotVisitor.h"
-#include "SlotVisitorInlineMethods.h"
+#include "SlotVisitorInlines.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/heap/HeapStatistics.cpp b/Source/JavaScriptCore/heap/HeapStatistics.cpp
index 8340bfa37..387621558 100644
--- a/Source/JavaScriptCore/heap/HeapStatistics.cpp
+++ b/Source/JavaScriptCore/heap/HeapStatistics.cpp
@@ -41,8 +41,8 @@ namespace JSC {
double HeapStatistics::s_startTime = 0.0;
double HeapStatistics::s_endTime = 0.0;
-Deque<double>* HeapStatistics::s_pauseTimeStarts = 0;
-Deque<double>* HeapStatistics::s_pauseTimeEnds = 0;
+Vector<double>* HeapStatistics::s_pauseTimeStarts = 0;
+Vector<double>* HeapStatistics::s_pauseTimeEnds = 0;
#if OS(UNIX)
@@ -50,8 +50,8 @@ void HeapStatistics::initialize()
{
ASSERT(Options::recordGCPauseTimes());
s_startTime = WTF::monotonicallyIncreasingTime();
- s_pauseTimeStarts = new Deque<double>();
- s_pauseTimeEnds = new Deque<double>();
+ s_pauseTimeStarts = new Vector<double>();
+ s_pauseTimeEnds = new Vector<double>();
}
void HeapStatistics::recordGCPauseTime(double start, double end)
@@ -82,8 +82,8 @@ void HeapStatistics::logStatistics()
if (Options::recordGCPauseTimes()) {
dataLog(", \"pause_times\": [");
- Deque<double>::iterator startIt = s_pauseTimeStarts->begin();
- Deque<double>::iterator endIt = s_pauseTimeEnds->begin();
+ Vector<double>::iterator startIt = s_pauseTimeStarts->begin();
+ Vector<double>::iterator endIt = s_pauseTimeEnds->begin();
if (startIt != s_pauseTimeStarts->end() && endIt != s_pauseTimeEnds->end()) {
dataLog("[%f, %f]", *startIt, *endIt);
++startIt;
diff --git a/Source/JavaScriptCore/heap/HeapStatistics.h b/Source/JavaScriptCore/heap/HeapStatistics.h
index 0800f0c16..ce7a40a79 100644
--- a/Source/JavaScriptCore/heap/HeapStatistics.h
+++ b/Source/JavaScriptCore/heap/HeapStatistics.h
@@ -49,8 +49,8 @@ public:
private:
static void logStatistics();
- static Deque<double>* s_pauseTimeStarts;
- static Deque<double>* s_pauseTimeEnds;
+ static Vector<double>* s_pauseTimeStarts;
+ static Vector<double>* s_pauseTimeEnds;
static double s_startTime;
static double s_endTime;
};
diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp
index 582439fd2..aa8785e9c 100644
--- a/Source/JavaScriptCore/heap/MarkStack.cpp
+++ b/Source/JavaScriptCore/heap/MarkStack.cpp
@@ -25,18 +25,18 @@
#include "config.h"
#include "MarkStack.h"
-#include "MarkStackInlineMethods.h"
+#include "MarkStackInlines.h"
-#include "CopiedSpace.h"
-#include "CopiedSpaceInlineMethods.h"
#include "ConservativeRoots.h"
+#include "CopiedSpace.h"
+#include "CopiedSpaceInlines.h"
#include "Heap.h"
#include "Options.h"
#include "JSArray.h"
#include "JSCell.h"
#include "JSObject.h"
-#include "SlotVisitorInlineMethods.h"
+#include "SlotVisitorInlines.h"
#include "Structure.h"
#include "WriteBarrier.h"
#include <wtf/Atomics.h>
diff --git a/Source/JavaScriptCore/heap/MarkStackInlineMethods.h b/Source/JavaScriptCore/heap/MarkStackInlines.h
index d3276d7fa..841ac06b8 100644
--- a/Source/JavaScriptCore/heap/MarkStackInlineMethods.h
+++ b/Source/JavaScriptCore/heap/MarkStackInlines.h
@@ -23,8 +23,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MarkStackInlineMethods_h
-#define MarkStackInlineMethods_h
+#ifndef MarkStackInlines_h
+#define MarkStackInlines_h
#include "GCThreadSharedData.h"
#include "MarkStack.h"
@@ -37,14 +37,14 @@ inline size_t MarkStackArray::postIncTop()
ASSERT(result == m_topSegment->m_top++);
return result;
}
-
+
inline size_t MarkStackArray::preDecTop()
{
size_t result = --m_top;
ASSERT(result == --m_topSegment->m_top);
return result;
}
-
+
inline void MarkStackArray::setTopForFullSegment()
{
ASSERT(m_topSegment->m_top == m_segmentCapacity);
@@ -110,4 +110,5 @@ inline size_t MarkStackArray::size()
} // namespace JSC
-#endif
+#endif // MarkStackInlines_h
+
diff --git a/Source/JavaScriptCore/heap/SlotVisitor.cpp b/Source/JavaScriptCore/heap/SlotVisitor.cpp
index 3919705d0..8b4d7397e 100644
--- a/Source/JavaScriptCore/heap/SlotVisitor.cpp
+++ b/Source/JavaScriptCore/heap/SlotVisitor.cpp
@@ -3,7 +3,7 @@
#include "ConservativeRoots.h"
#include "CopiedSpace.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "GCThread.h"
#include "JSArray.h"
#include "JSDestructibleObject.h"
diff --git a/Source/JavaScriptCore/heap/SlotVisitor.h b/Source/JavaScriptCore/heap/SlotVisitor.h
index dcd4b75ef..34b1bc80b 100644
--- a/Source/JavaScriptCore/heap/SlotVisitor.h
+++ b/Source/JavaScriptCore/heap/SlotVisitor.h
@@ -27,7 +27,7 @@
#define SlotVisitor_h
#include "HandleTypes.h"
-#include "MarkStackInlineMethods.h"
+#include "MarkStackInlines.h"
#include <wtf/text/StringHash.h>
diff --git a/Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h b/Source/JavaScriptCore/heap/SlotVisitorInlines.h
index e5908bf36..b0f30b6ca 100644
--- a/Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h
+++ b/Source/JavaScriptCore/heap/SlotVisitorInlines.h
@@ -23,10 +23,10 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SlotVisitorInlineMethods_h
-#define SlotVisitorInlineMethods_h
+#ifndef SlotVisitorInlines_h
+#define SlotVisitorInlines_h
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "Options.h"
#include "SlotVisitor.h"
@@ -170,5 +170,5 @@ inline void SlotVisitor::copyLater(void* ptr, size_t bytes)
} // namespace JSC
-#endif // SlotVisitorInlineMethods_h
+#endif // SlotVisitorInlines_h
diff --git a/Source/JavaScriptCore/heap/WeakBlock.cpp b/Source/JavaScriptCore/heap/WeakBlock.cpp
index 99e306b85..5f01f34b3 100644
--- a/Source/JavaScriptCore/heap/WeakBlock.cpp
+++ b/Source/JavaScriptCore/heap/WeakBlock.cpp
@@ -34,18 +34,14 @@
namespace JSC {
-WeakBlock* WeakBlock::create()
+WeakBlock* WeakBlock::create(DeadBlock* block)
{
- void* allocation = fastMalloc(blockSize);
- return new (NotNull, allocation) WeakBlock;
+ Region* region = block->region();
+ return new (NotNull, block) WeakBlock(region);
}
-void WeakBlock::destroy(WeakBlock* block)
-{
- fastFree(block);
-}
-
-WeakBlock::WeakBlock()
+WeakBlock::WeakBlock(Region* region)
+ : HeapBlock<WeakBlock>(region)
{
for (size_t i = 0; i < weakImplCount(); ++i) {
WeakImpl* weakImpl = &weakImpls()[i];
diff --git a/Source/JavaScriptCore/heap/WeakBlock.h b/Source/JavaScriptCore/heap/WeakBlock.h
index 6461f7b2f..fd28101fd 100644
--- a/Source/JavaScriptCore/heap/WeakBlock.h
+++ b/Source/JavaScriptCore/heap/WeakBlock.h
@@ -34,14 +34,15 @@
namespace JSC {
+class DeadBlock;
class HeapRootVisitor;
class JSValue;
class WeakHandleOwner;
-class WeakBlock : public DoublyLinkedListNode<WeakBlock> {
+class WeakBlock : public HeapBlock<WeakBlock> {
public:
friend class WTF::DoublyLinkedListNode<WeakBlock>;
- static const size_t blockSize = 3 * KB; // 5% of MarkedBlock size
+ static const size_t blockSize = 4 * KB; // 5% of MarkedBlock size
struct FreeCell {
FreeCell* next;
@@ -55,8 +56,7 @@ public:
FreeCell* freeList;
};
- static WeakBlock* create();
- static void destroy(WeakBlock*);
+ static WeakBlock* create(DeadBlock*);
static WeakImpl* asWeakImpl(FreeCell*);
@@ -73,15 +73,13 @@ public:
private:
static FreeCell* asFreeCell(WeakImpl*);
- WeakBlock();
+ WeakBlock(Region*);
WeakImpl* firstWeakImpl();
void finalize(WeakImpl*);
WeakImpl* weakImpls();
size_t weakImplCount();
void addToFreeList(FreeCell**, WeakImpl*);
- WeakBlock* m_prev;
- WeakBlock* m_next;
SweepResult m_sweepResult;
};
diff --git a/Source/JavaScriptCore/heap/WeakSet.cpp b/Source/JavaScriptCore/heap/WeakSet.cpp
index 2804968f8..67b1d0613 100644
--- a/Source/JavaScriptCore/heap/WeakSet.cpp
+++ b/Source/JavaScriptCore/heap/WeakSet.cpp
@@ -36,7 +36,7 @@ WeakSet::~WeakSet()
WeakBlock* next = 0;
for (WeakBlock* block = m_blocks.head(); block; block = next) {
next = block->next();
- WeakBlock::destroy(block);
+ heap()->blockAllocator().deallocate(WeakBlock::destroy(block));
}
m_blocks.clear();
}
@@ -73,7 +73,7 @@ WeakBlock::FreeCell* WeakSet::tryFindAllocator()
WeakBlock::FreeCell* WeakSet::addAllocator()
{
- WeakBlock* block = WeakBlock::create();
+ WeakBlock* block = WeakBlock::create(heap()->blockAllocator().allocate<WeakBlock>());
heap()->didAllocate(WeakBlock::blockSize);
m_blocks.append(block);
WeakBlock::SweepResult sweepResult = block->takeSweepResult();
diff --git a/Source/JavaScriptCore/jit/HostCallReturnValue.cpp b/Source/JavaScriptCore/jit/HostCallReturnValue.cpp
index c4d2e6ad9..967c499b9 100644
--- a/Source/JavaScriptCore/jit/HostCallReturnValue.cpp
+++ b/Source/JavaScriptCore/jit/HostCallReturnValue.cpp
@@ -29,7 +29,7 @@
#include "CallFrame.h"
#include <wtf/InlineASM.h>
#include "JSObject.h"
-#include "JSValueInlineMethods.h"
+#include "JSValueInlines.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index 3102c7693..ffd18b571 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -38,7 +38,7 @@ JSC::MacroAssemblerX86Common::SSE2CheckState JSC::MacroAssemblerX86Common::s_sse
#include <wtf/CryptographicallyRandomNumber.h>
#include "DFGNode.h" // for DFG_SUCCESS_STATS
#include "Interpreter.h"
-#include "JITInlineMethods.h"
+#include "JITInlines.h"
#include "JITStubCall.h"
#include "JSArray.h"
#include "JSFunction.h"
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index dcf87d352..9b0879fe2 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -474,7 +474,9 @@ namespace JSC {
// Property is int-checked and zero extended. Base is cell checked.
// Structure is already profiled. Returns the slow cases. Fall-through
// case contains result in regT0, and it is not yet profiled.
- JumpList emitContiguousGetByVal(Instruction*, PatchableJump& badType);
+ JumpList emitInt32GetByVal(Instruction* instruction, PatchableJump& badType) { return emitContiguousGetByVal(instruction, badType, Int32Shape); }
+ JumpList emitDoubleGetByVal(Instruction*, PatchableJump& badType);
+ JumpList emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape = ContiguousShape);
JumpList emitArrayStorageGetByVal(Instruction*, PatchableJump& badType);
JumpList emitIntTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize, TypedArraySignedness);
JumpList emitFloatTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize);
@@ -483,7 +485,20 @@ namespace JSC {
// The value to store is not yet loaded. Property is int-checked and
// zero-extended. Base is cell checked. Structure is already profiled.
// returns the slow cases.
- JumpList emitContiguousPutByVal(Instruction*, PatchableJump& badType);
+ JumpList emitInt32PutByVal(Instruction* currentInstruction, PatchableJump& badType)
+ {
+ return emitGenericContiguousPutByVal<Int32Shape>(currentInstruction, badType);
+ }
+ JumpList emitDoublePutByVal(Instruction* currentInstruction, PatchableJump& badType)
+ {
+ return emitGenericContiguousPutByVal<DoubleShape>(currentInstruction, badType);
+ }
+ JumpList emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
+ {
+ return emitGenericContiguousPutByVal<ContiguousShape>(currentInstruction, badType);
+ }
+ template<IndexingType indexingShape>
+ JumpList emitGenericContiguousPutByVal(Instruction*, PatchableJump& badType);
JumpList emitArrayStoragePutByVal(Instruction*, PatchableJump& badType);
JumpList emitIntTypedArrayPutByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize, TypedArraySignedness, TypedArrayRounding);
JumpList emitFloatTypedArrayPutByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize);
diff --git a/Source/JavaScriptCore/jit/JITArithmetic.cpp b/Source/JavaScriptCore/jit/JITArithmetic.cpp
index 21d59bc33..bcb3dd74a 100644
--- a/Source/JavaScriptCore/jit/JITArithmetic.cpp
+++ b/Source/JavaScriptCore/jit/JITArithmetic.cpp
@@ -29,7 +29,7 @@
#include "JIT.h"
#include "CodeBlock.h"
-#include "JITInlineMethods.h"
+#include "JITInlines.h"
#include "JITStubCall.h"
#include "JITStubs.h"
#include "JSArray.h"
@@ -1090,18 +1090,20 @@ void JIT::emit_op_div(Instruction* currentInstruction)
// access). So if we are DFG compiling anything in the program, we want this code to
// ensure that it produces integers whenever possible.
- // FIXME: This will fail to convert to integer if the result is zero. We should
- // distinguish between positive zero and negative zero here.
-
JumpList notInteger;
branchConvertDoubleToInt32(fpRegT0, regT0, notInteger, fpRegT1);
// If we've got an integer, we might as well make that the result of the division.
emitFastArithReTagImmediate(regT0, regT0);
Jump isInteger = jump();
notInteger.link(this);
- add32(TrustedImm32(1), AbsoluteAddress(&m_codeBlock->addSpecialFastCaseProfile(m_bytecodeOffset)->m_counter));
moveDoubleTo64(fpRegT0, regT0);
+ Jump doubleZero = branchTest64(Zero, regT0);
+ add32(TrustedImm32(1), AbsoluteAddress(&m_codeBlock->addSpecialFastCaseProfile(m_bytecodeOffset)->m_counter));
sub64(tagTypeNumberRegister, regT0);
+ Jump trueDouble = jump();
+ doubleZero.link(this);
+ move(tagTypeNumberRegister, regT0);
+ trueDouble.link(this);
isInteger.link(this);
#else
// Double result.
diff --git a/Source/JavaScriptCore/jit/JITArithmetic32_64.cpp b/Source/JavaScriptCore/jit/JITArithmetic32_64.cpp
index 62a359eeb..960d06091 100644
--- a/Source/JavaScriptCore/jit/JITArithmetic32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITArithmetic32_64.cpp
@@ -30,7 +30,7 @@
#include "JIT.h"
#include "CodeBlock.h"
-#include "JITInlineMethods.h"
+#include "JITInlines.h"
#include "JITStubCall.h"
#include "JITStubs.h"
#include "JSArray.h"
diff --git a/Source/JavaScriptCore/jit/JITCall.cpp b/Source/JavaScriptCore/jit/JITCall.cpp
index 074bf7f97..006c5b741 100644
--- a/Source/JavaScriptCore/jit/JITCall.cpp
+++ b/Source/JavaScriptCore/jit/JITCall.cpp
@@ -31,7 +31,7 @@
#include "Arguments.h"
#include "CodeBlock.h"
-#include "JITInlineMethods.h"
+#include "JITInlines.h"
#include "JITStubCall.h"
#include "JSArray.h"
#include "JSFunction.h"
diff --git a/Source/JavaScriptCore/jit/JITCall32_64.cpp b/Source/JavaScriptCore/jit/JITCall32_64.cpp
index ad827cdf9..ecd5cf126 100644
--- a/Source/JavaScriptCore/jit/JITCall32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITCall32_64.cpp
@@ -32,7 +32,7 @@
#include "Arguments.h"
#include "CodeBlock.h"
#include "Interpreter.h"
-#include "JITInlineMethods.h"
+#include "JITInlines.h"
#include "JITStubCall.h"
#include "JSArray.h"
#include "JSFunction.h"
diff --git a/Source/JavaScriptCore/jit/JITExceptions.cpp b/Source/JavaScriptCore/jit/JITExceptions.cpp
index f6cec24bd..aeb869474 100644
--- a/Source/JavaScriptCore/jit/JITExceptions.cpp
+++ b/Source/JavaScriptCore/jit/JITExceptions.cpp
@@ -39,7 +39,7 @@ namespace JSC {
ExceptionHandler genericThrow(JSGlobalData* globalData, ExecState* callFrame, JSValue exceptionValue, unsigned vPCIndex)
{
ASSERT(exceptionValue);
-
+
globalData->exception = JSValue();
HandlerInfo* handler = globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex); // This may update callFrame & exceptionValue!
globalData->exception = exceptionValue;
diff --git a/Source/JavaScriptCore/jit/JITInlineMethods.h b/Source/JavaScriptCore/jit/JITInlines.h
index 410bdf710..e6f95b94c 100644
--- a/Source/JavaScriptCore/jit/JITInlineMethods.h
+++ b/Source/JavaScriptCore/jit/JITInlines.h
@@ -23,8 +23,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef JITInlineMethods_h
-#define JITInlineMethods_h
+#ifndef JITInlines_h
+#define JITInlines_h
#if ENABLE(JIT)
@@ -528,12 +528,12 @@ inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfi
#endif
}
-static inline bool arrayProfileSaw(ArrayProfile* profile, IndexingType capability)
+static inline bool arrayProfileSaw(ArrayModes arrayModes, IndexingType capability)
{
#if ENABLE(VALUE_PROFILER)
- return !!(profile->observedArrayModes() & (asArrayModes(NonArray | capability) | asArrayModes(ArrayClass | capability)));
+ return arrayModesInclude(arrayModes, capability);
#else
- UNUSED_PARAM(profile);
+ UNUSED_PARAM(arrayModes);
UNUSED_PARAM(capability);
return false;
#endif
@@ -541,9 +541,20 @@ static inline bool arrayProfileSaw(ArrayProfile* profile, IndexingType capabilit
inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile)
{
- if (arrayProfileSaw(profile, ArrayStorageShape))
+#if ENABLE(VALUE_PROFILER)
+ profile->computeUpdatedPrediction(m_codeBlock);
+ ArrayModes arrayModes = profile->observedArrayModes();
+ if (arrayProfileSaw(arrayModes, DoubleShape))
+ return JITDouble;
+ if (arrayProfileSaw(arrayModes, Int32Shape))
+ return JITInt32;
+ if (arrayProfileSaw(arrayModes, ArrayStorageShape))
return JITArrayStorage;
return JITContiguous;
+#else
+ UNUSED_PARAM(profile);
+ return JITContiguous;
+#endif
}
#if USE(JSVALUE32_64)
@@ -998,4 +1009,5 @@ ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg)
#endif // ENABLE(JIT)
-#endif
+#endif // JITInlines_h
+
diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp
index 249dcbac9..3053918b8 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp
@@ -29,9 +29,9 @@
#include "JIT.h"
#include "Arguments.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "Heap.h"
-#include "JITInlineMethods.h"
+#include "JITInlines.h"
#include "JITStubCall.h"
#include "JSArray.h"
#include "JSCell.h"
@@ -1625,7 +1625,7 @@ void JIT::emit_resolve_operations(ResolveOperations* resolveOperations, const in
break;
case ResolveOperation::ReturnScopeAsBase:
emitStoreCell(*baseVR, scope);
- ASSERT(!value);
+ ASSERT(value == regT0);
move(scope, value);
#if USE(JSVALUE32_64)
move(TrustedImm32(JSValue::CellTag), valueTag);
@@ -1952,6 +1952,7 @@ void JIT::emit_op_new_array(Instruction* currentInstruction)
JITStubCall stubCall(this, cti_op_new_array);
stubCall.addArgument(TrustedImm32(currentInstruction[2].u.operand));
stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
+ stubCall.addArgument(TrustedImmPtr(currentInstruction[4].u.arrayAllocationProfile));
stubCall.call(currentInstruction[1].u.operand);
}
@@ -1963,6 +1964,7 @@ void JIT::emit_op_new_array_with_size(Instruction* currentInstruction)
#else
stubCall.addArgument(currentInstruction[2].u.operand);
#endif
+ stubCall.addArgument(TrustedImmPtr(currentInstruction[3].u.arrayAllocationProfile));
stubCall.call(currentInstruction[1].u.operand);
}
@@ -1971,6 +1973,7 @@ void JIT::emit_op_new_array_buffer(Instruction* currentInstruction)
JITStubCall stubCall(this, cti_op_new_array_buffer);
stubCall.addArgument(TrustedImm32(currentInstruction[2].u.operand));
stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
+ stubCall.addArgument(TrustedImmPtr(currentInstruction[4].u.arrayAllocationProfile));
stubCall.call(currentInstruction[1].u.operand);
}
diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
index 9c5d260ab..23361c099 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -30,7 +30,7 @@
#if USE(JSVALUE32_64)
#include "JIT.h"
-#include "JITInlineMethods.h"
+#include "JITInlines.h"
#include "JITStubCall.h"
#include "JSArray.h"
#include "JSCell.h"
diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
index 6362598f4..3110be38c 100644
--- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
+++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
@@ -32,7 +32,7 @@
#include "GCAwareJITStubRoutine.h"
#include "GetterSetter.h"
#include "Interpreter.h"
-#include "JITInlineMethods.h"
+#include "JITInlines.h"
#include "JITStubCall.h"
#include "JSArray.h"
#include "JSFunction.h"
@@ -98,7 +98,7 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
unsigned base = currentInstruction[2].u.operand;
unsigned property = currentInstruction[3].u.operand;
ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
-
+
emitGetVirtualRegisters(base, regT0, property, regT1);
emitJumpSlowCaseIfNotImmediateInteger(regT1);
@@ -120,6 +120,12 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
JITArrayMode mode = chooseArrayMode(profile);
switch (mode) {
+ case JITInt32:
+ slowCases = emitInt32GetByVal(currentInstruction, badType);
+ break;
+ case JITDouble:
+ slowCases = emitDoubleGetByVal(currentInstruction, badType);
+ break;
case JITContiguous:
slowCases = emitContiguousGetByVal(currentInstruction, badType);
break;
@@ -148,11 +154,26 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
}
-JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType)
+JIT::JumpList JIT::emitDoubleGetByVal(Instruction*, PatchableJump& badType)
{
JumpList slowCases;
- badType = patchableBranch32(NotEqual, regT2, TrustedImm32(ContiguousShape));
+ badType = patchableBranch32(NotEqual, regT2, TrustedImm32(DoubleShape));
+ loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
+ slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength())));
+ loadDouble(BaseIndex(regT2, regT1, TimesEight), fpRegT0);
+ slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
+ moveDoubleTo64(fpRegT0, regT0);
+ sub64(tagTypeNumberRegister, regT0);
+
+ return slowCases;
+}
+
+JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape)
+{
+ JumpList slowCases;
+
+ badType = patchableBranch32(NotEqual, regT2, TrustedImm32(expectedShape));
loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength())));
load64(BaseIndex(regT2, regT1, TimesEight), regT0);
@@ -304,6 +325,12 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
JITArrayMode mode = chooseArrayMode(profile);
switch (mode) {
+ case JITInt32:
+ slowCases = emitInt32PutByVal(currentInstruction, badType);
+ break;
+ case JITDouble:
+ slowCases = emitDoublePutByVal(currentInstruction, badType);
+ break;
case JITContiguous:
slowCases = emitContiguousPutByVal(currentInstruction, badType);
break;
@@ -325,24 +352,49 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
emitWriteBarrier(regT0, regT3, regT1, regT3, ShouldFilterImmediates, WriteBarrierForPropertyAccess);
}
-JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
+template<IndexingType indexingShape>
+JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
{
unsigned value = currentInstruction[3].u.operand;
ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
- badType = patchableBranch32(NotEqual, regT2, TrustedImm32(ContiguousShape));
+ JumpList slowCases;
+
+ badType = patchableBranch32(NotEqual, regT2, TrustedImm32(indexingShape));
loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
Jump outOfBounds = branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength()));
Label storeResult = label();
emitGetVirtualRegister(value, regT3);
- store64(regT3, BaseIndex(regT2, regT1, TimesEight));
+ switch (indexingShape) {
+ case Int32Shape:
+ slowCases.append(emitJumpIfNotImmediateInteger(regT3));
+ store64(regT3, BaseIndex(regT2, regT1, TimesEight));
+ break;
+ case DoubleShape: {
+ Jump notInt = emitJumpIfNotImmediateInteger(regT3);
+ convertInt32ToDouble(regT3, fpRegT0);
+ Jump ready = jump();
+ notInt.link(this);
+ add64(tagTypeNumberRegister, regT3);
+ move64ToDouble(regT3, fpRegT0);
+ slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
+ ready.link(this);
+ storeDouble(fpRegT0, BaseIndex(regT2, regT1, TimesEight));
+ break;
+ }
+ case ContiguousShape:
+ store64(regT3, BaseIndex(regT2, regT1, TimesEight));
+ break;
+ default:
+ CRASH();
+ break;
+ }
Jump done = jump();
outOfBounds.link(this);
- JumpList slowCases;
slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfVectorLength())));
emitArrayProfileStoreToHoleSpecialCase(profile);
@@ -394,12 +446,23 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
unsigned base = currentInstruction[1].u.operand;
unsigned property = currentInstruction[2].u.operand;
unsigned value = currentInstruction[3].u.operand;
+ ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
linkSlowCase(iter); // property int32 check
linkSlowCaseIfNotJSCell(iter, base); // base cell check
linkSlowCase(iter); // base not array check
linkSlowCase(iter); // out of bounds
+ JITArrayMode mode = chooseArrayMode(profile);
+ switch (mode) {
+ case JITInt32:
+ case JITDouble:
+ linkSlowCase(iter); // value type check
+ break;
+ default:
+ break;
+ }
+
Label slowPath = label();
JITStubCall stubPutByValCall(this, cti_op_put_by_val);
@@ -1312,6 +1375,12 @@ void JIT::privateCompileGetByVal(ByValInfo* byValInfo, ReturnAddressPtr returnAd
JumpList slowCases;
switch (arrayMode) {
+ case JITInt32:
+ slowCases = emitInt32GetByVal(currentInstruction, badType);
+ break;
+ case JITDouble:
+ slowCases = emitDoubleGetByVal(currentInstruction, badType);
+ break;
case JITContiguous:
slowCases = emitContiguousGetByVal(currentInstruction, badType);
break;
@@ -1375,6 +1444,12 @@ void JIT::privateCompilePutByVal(ByValInfo* byValInfo, ReturnAddressPtr returnAd
JumpList slowCases;
switch (arrayMode) {
+ case JITInt32:
+ slowCases = emitInt32PutByVal(currentInstruction, badType);
+ break;
+ case JITDouble:
+ slowCases = emitDoublePutByVal(currentInstruction, badType);
+ break;
case JITContiguous:
slowCases = emitContiguousPutByVal(currentInstruction, badType);
break;
diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
index 939766f04..414827420 100644
--- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
@@ -32,7 +32,7 @@
#include "CodeBlock.h"
#include "GCAwareJITStubRoutine.h"
#include "Interpreter.h"
-#include "JITInlineMethods.h"
+#include "JITInlines.h"
#include "JITStubCall.h"
#include "JSArray.h"
#include "JSFunction.h"
@@ -153,6 +153,12 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
JITArrayMode mode = chooseArrayMode(profile);
switch (mode) {
+ case JITInt32:
+ slowCases = emitInt32GetByVal(currentInstruction, badType);
+ break;
+ case JITDouble:
+ slowCases = emitDoubleGetByVal(currentInstruction, badType);
+ break;
case JITContiguous:
slowCases = emitContiguousGetByVal(currentInstruction, badType);
break;
@@ -181,11 +187,11 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
}
-JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType)
+JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape)
{
JumpList slowCases;
- badType = patchableBranch32(NotEqual, regT1, TrustedImm32(ContiguousShape));
+ badType = patchableBranch32(NotEqual, regT1, TrustedImm32(expectedShape));
loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength())));
@@ -197,6 +203,22 @@ JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType)
return slowCases;
}
+JIT::JumpList JIT::emitDoubleGetByVal(Instruction*, PatchableJump& badType)
+{
+ JumpList slowCases;
+
+ badType = patchableBranch32(NotEqual, regT1, TrustedImm32(DoubleShape));
+
+ loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
+ slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength())));
+
+ loadDouble(BaseIndex(regT3, regT2, TimesEight), fpRegT0);
+ slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
+ moveDoubleToInts(fpRegT0, regT0, regT1);
+
+ return slowCases;
+}
+
JIT::JumpList JIT::emitArrayStorageGetByVal(Instruction*, PatchableJump& badType)
{
JumpList slowCases;
@@ -270,6 +292,12 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
JITArrayMode mode = chooseArrayMode(profile);
switch (mode) {
+ case JITInt32:
+ slowCases = emitInt32PutByVal(currentInstruction, badType);
+ break;
+ case JITDouble:
+ slowCases = emitDoublePutByVal(currentInstruction, badType);
+ break;
case JITContiguous:
slowCases = emitContiguousPutByVal(currentInstruction, badType);
break;
@@ -289,7 +317,8 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
}
-JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
+template<IndexingType indexingShape>
+JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
{
unsigned value = currentInstruction[3].u.operand;
ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
@@ -303,8 +332,30 @@ JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, Patch
Label storeResult = label();
emitLoad(value, regT1, regT0);
- store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
- store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ switch (indexingShape) {
+ case Int32Shape:
+ slowCases.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ // Fall through.
+ case ContiguousShape:
+ store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+ store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ break;
+ case DoubleShape: {
+ Jump notInt = branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag));
+ convertInt32ToDouble(regT0, fpRegT0);
+ Jump ready = jump();
+ notInt.link(this);
+ moveIntsToDouble(regT0, regT1, fpRegT0, fpRegT1);
+ slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
+ ready.link(this);
+ storeDouble(fpRegT0, BaseIndex(regT3, regT2, TimesEight));
+ break;
+ }
+ default:
+ CRASH();
+ break;
+ }
+
Jump done = jump();
outOfBounds.link(this);
@@ -364,12 +415,23 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
unsigned base = currentInstruction[1].u.operand;
unsigned property = currentInstruction[2].u.operand;
unsigned value = currentInstruction[3].u.operand;
+ ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
linkSlowCase(iter); // property int32 check
linkSlowCaseIfNotJSCell(iter, base); // base cell check
linkSlowCase(iter); // base not array check
linkSlowCase(iter); // out of bounds
+ JITArrayMode mode = chooseArrayMode(profile);
+ switch (mode) {
+ case JITInt32:
+ case JITDouble:
+ linkSlowCase(iter); // value type check
+ break;
+ default:
+ break;
+ }
+
Label slowPath = label();
JITStubCall stubPutByValCall(this, cti_op_put_by_val);
diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp
index 5ddb98dee..521dfacfd 100644
--- a/Source/JavaScriptCore/jit/JITStubs.cpp
+++ b/Source/JavaScriptCore/jit/JITStubs.cpp
@@ -1877,6 +1877,11 @@ DEFINE_STUB_FUNCTION(void, optimize)
ASSERT(optimizedCodeBlock->getJITType() == JITCode::DFGJIT);
if (void* address = DFG::prepareOSREntry(callFrame, optimizedCodeBlock, bytecodeIndex)) {
+ if (Options::showDFGDisassembly()) {
+ dataLog(
+ "Performing OSR from code block %p to code block %p, address %p to %p.\n",
+ codeBlock, optimizedCodeBlock, (STUB_RETURN_ADDRESS).value(), address);
+ }
#if ENABLE(JIT_VERBOSE_OSR)
dataLog("Optimizing %p succeeded, performing OSR after a delay of %u.\n", codeBlock, codeBlock->optimizationDelayCounter());
#endif
@@ -2228,21 +2233,21 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_array)
{
STUB_INIT_STACK_FRAME(stackFrame);
- return constructArray(stackFrame.callFrame, reinterpret_cast<JSValue*>(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()]), stackFrame.args[1].int32());
+ return constructArray(stackFrame.callFrame, stackFrame.args[2].arrayAllocationProfile(), reinterpret_cast<JSValue*>(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()]), stackFrame.args[1].int32());
}
DEFINE_STUB_FUNCTION(JSObject*, op_new_array_with_size)
{
STUB_INIT_STACK_FRAME(stackFrame);
- return constructArrayWithSizeQuirk(stackFrame.callFrame, stackFrame.callFrame->lexicalGlobalObject(), stackFrame.args[0].jsValue());
+ return constructArrayWithSizeQuirk(stackFrame.callFrame, stackFrame.args[1].arrayAllocationProfile(), stackFrame.callFrame->lexicalGlobalObject(), stackFrame.args[0].jsValue());
}
DEFINE_STUB_FUNCTION(JSObject*, op_new_array_buffer)
{
STUB_INIT_STACK_FRAME(stackFrame);
- return constructArray(stackFrame.callFrame, stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32());
+ return constructArray(stackFrame.callFrame, stackFrame.args[2].arrayAllocationProfile(), stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32());
}
DEFINE_STUB_FUNCTION(void, op_init_global_const_check)
@@ -2470,7 +2475,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val)
JSValue baseValue = stackFrame.args[0].jsValue();
JSValue subscript = stackFrame.args[1].jsValue();
JSValue value = stackFrame.args[2].jsValue();
-
+
if (baseValue.isObject() && subscript.isInt32()) {
// See if it's worth optimizing at all.
JSObject* object = asObject(baseValue);
diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h
index 5761236b1..3bf13bbdf 100644
--- a/Source/JavaScriptCore/jit/JITStubs.h
+++ b/Source/JavaScriptCore/jit/JITStubs.h
@@ -45,6 +45,7 @@ namespace JSC {
struct StructureStubInfo;
+ class ArrayAllocationProfile;
class CodeBlock;
class ExecutablePool;
class FunctionExecutable;
@@ -85,6 +86,7 @@ namespace JSC {
ReturnAddressPtr returnAddress() { return ReturnAddressPtr(asPointer); }
ResolveOperations* resolveOperations() { return static_cast<ResolveOperations*>(asPointer); }
PutToBaseOperation* putToBaseOperation() { return static_cast<PutToBaseOperation*>(asPointer); }
+ ArrayAllocationProfile* arrayAllocationProfile() { return static_cast<ArrayAllocationProfile*>(asPointer); }
};
struct TrampolineStructure {
diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp
index b8cf49da6..07a05b0c9 100644
--- a/Source/JavaScriptCore/jsc.cpp
+++ b/Source/JavaScriptCore/jsc.cpp
@@ -22,10 +22,10 @@
#include "config.h"
-#include "ButterflyInlineMethods.h"
+#include "ButterflyInlines.h"
#include "BytecodeGenerator.h"
#include "Completion.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "ExceptionHelpers.h"
#include "HeapStatistics.h"
#include "InitializeThreading.h"
@@ -231,7 +231,7 @@ protected:
addConstructableFunction(globalData, "Float32Array", constructJSFloat32Array, 1);
addConstructableFunction(globalData, "Float64Array", constructJSFloat64Array, 1);
- JSArray* array = constructEmptyArray(globalExec());
+ JSArray* array = constructEmptyArray(globalExec(), 0);
for (size_t i = 0; i < arguments.size(); ++i)
array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
putDirect(globalData, Identifier(globalExec(), "arguments"), array);
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
index ba44bf404..8a578ffac 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
@@ -275,7 +275,7 @@ inline bool shouldJIT(ExecState* exec)
// Returns true if we should try to OSR.
inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec)
{
- codeBlock->updateAllPredictions();
+ codeBlock->updateAllValueProfilePredictions();
if (!codeBlock->checkIfJITThresholdReached()) {
#if ENABLE(JIT_VERBOSE_OSR)
@@ -510,19 +510,19 @@ LLINT_SLOW_PATH_DECL(slow_path_new_object)
LLINT_SLOW_PATH_DECL(slow_path_new_array)
{
LLINT_BEGIN();
- LLINT_RETURN(constructArray(exec, bitwise_cast<JSValue*>(&LLINT_OP(2)), pc[3].u.operand));
+ LLINT_RETURN(constructArray(exec, pc[4].u.arrayAllocationProfile, bitwise_cast<JSValue*>(&LLINT_OP(2)), pc[3].u.operand));
}
LLINT_SLOW_PATH_DECL(slow_path_new_array_with_size)
{
LLINT_BEGIN();
- LLINT_RETURN(constructArrayWithSizeQuirk(exec, exec->lexicalGlobalObject(), LLINT_OP_C(2).jsValue()));
+ LLINT_RETURN(constructArrayWithSizeQuirk(exec, pc[3].u.arrayAllocationProfile, exec->lexicalGlobalObject(), LLINT_OP_C(2).jsValue()));
}
LLINT_SLOW_PATH_DECL(slow_path_new_array_buffer)
{
LLINT_BEGIN();
- LLINT_RETURN(constructArray(exec, exec->codeBlock()->constantBuffer(pc[2].u.operand), pc[3].u.operand));
+ LLINT_RETURN(constructArray(exec, pc[4].u.arrayAllocationProfile, exec->codeBlock()->constantBuffer(pc[2].u.operand), pc[3].u.operand));
}
LLINT_SLOW_PATH_DECL(slow_path_new_regexp)
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index ba5b67df4..00d5c4f6f 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -88,10 +88,13 @@ else
end
# Constant for reasoning about butterflies.
-const IsArray = 1
-const IndexingShapeMask = 30
-const ContiguousShape = 26
-const ArrayStorageShape = 28
+const IsArray = 1
+const IndexingShapeMask = 30
+const NoIndexingShape = 0
+const Int32Shape = 20
+const DoubleShape = 22
+const ContiguousShape = 26
+const ArrayStorageShape = 28
const SlowPutArrayStorageShape = 30
# Type constants.
@@ -462,19 +465,19 @@ end
_llint_op_new_array:
traceExecution()
callSlowPath(_llint_slow_path_new_array)
- dispatch(4)
+ dispatch(5)
_llint_op_new_array_with_size:
traceExecution()
callSlowPath(_llint_slow_path_new_array_with_size)
- dispatch(3)
+ dispatch(4)
_llint_op_new_array_buffer:
traceExecution()
callSlowPath(_llint_slow_path_new_array_buffer)
- dispatch(4)
+ dispatch(5)
_llint_op_new_regexp:
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
index ffb146247..e3ef909f5 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -1185,7 +1185,9 @@ _llint_op_get_by_val:
loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow)
loadp JSObject::m_butterfly[t0], t3
andi IndexingShapeMask, t2
+ bieq t2, Int32Shape, .opGetByValIsContiguous
bineq t2, ContiguousShape, .opGetByValNotContiguous
+.opGetByValIsContiguous:
biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow
loadi TagOffset[t3, t1, 8], t2
@@ -1193,6 +1195,16 @@ _llint_op_get_by_val:
jmp .opGetByValDone
.opGetByValNotContiguous:
+ bineq t2, DoubleShape, .opGetByValNotDouble
+ biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow
+ loadd [t3, t1, 8], ft0
+ bdnequn ft0, ft0, .opGetByValSlow
+ # FIXME: This could be massively optimized.
+ fd2ii ft0, t1, t2
+ loadi 4[PC], t0
+ jmp .opGetByValNotEmpty
+
+.opGetByValNotDouble:
subi ArrayStorageShape, t2
bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow
biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t3], .opGetByValSlow
@@ -1202,6 +1214,7 @@ _llint_op_get_by_val:
.opGetByValDone:
loadi 4[PC], t0
bieq t2, EmptyValueTag, .opGetByValSlow
+.opGetByValNotEmpty:
storei t2, TagOffset[cfr, t0, 8]
storei t1, PayloadOffset[cfr, t0, 8]
loadi 20[PC], t0
@@ -1270,6 +1283,24 @@ _llint_op_get_by_pname:
dispatch(7)
+macro contiguousPutByVal(storeCallback)
+ biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .outOfBounds
+.storeResult:
+ loadi 12[PC], t2
+ storeCallback(t2, t1, t0, t3)
+ dispatch(5)
+
+.outOfBounds:
+ biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow
+ if VALUE_PROFILER
+ loadp 16[PC], t2
+ storeb 1, ArrayProfile::m_mayStoreToHole[t2]
+ end
+ addi 1, t3, t2
+ storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0]
+ jmp .storeResult
+end
+
_llint_op_put_by_val:
traceExecution()
loadi 4[PC], t0
@@ -1281,26 +1312,42 @@ _llint_op_put_by_val:
loadConstantOrVariablePayload(t0, Int32Tag, t3, .opPutByValSlow)
loadp JSObject::m_butterfly[t1], t0
andi IndexingShapeMask, t2
- bineq t2, ContiguousShape, .opPutByValNotContiguous
+ bineq t2, Int32Shape, .opPutByValNotInt32
+ contiguousPutByVal(
+ macro (operand, scratch, base, index)
+ loadConstantOrVariablePayload(operand, Int32Tag, scratch, .opPutByValSlow)
+ storei Int32Tag, TagOffset[base, index, 8]
+ storei scratch, PayloadOffset[base, index, 8]
+ end)
- biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .opPutByValContiguousOutOfBounds
-.opPutByValContiguousStoreResult:
- loadi 12[PC], t2
- loadConstantOrVariable2Reg(t2, t1, t2)
- writeBarrier(t1, t2)
- storei t1, TagOffset[t0, t3, 8]
- storei t2, PayloadOffset[t0, t3, 8]
- dispatch(5)
+.opPutByValNotInt32:
+ bineq t2, DoubleShape, .opPutByValNotDouble
+ contiguousPutByVal(
+ macro (operand, scratch, base, index)
+ const tag = scratch
+ const payload = operand
+ loadConstantOrVariable2Reg(operand, tag, payload)
+ bineq tag, Int32Tag, .notInt
+ ci2d payload, ft0
+ jmp .ready
+ .notInt:
+ fii2d payload, tag, ft0
+ bdnequn ft0, ft0, .opPutByValSlow
+ .ready:
+ stored ft0, [base, index, 8]
+ end)
-.opPutByValContiguousOutOfBounds:
- biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow
- if VALUE_PROFILER
- loadp 16[PC], t1
- storeb 1, ArrayProfile::m_mayStoreToHole[t1]
- end
- addi 1, t3, t2
- storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0]
- jmp .opPutByValContiguousStoreResult
+.opPutByValNotDouble:
+ bineq t2, ContiguousShape, .opPutByValNotContiguous
+ contiguousPutByVal(
+ macro (operand, scratch, base, index)
+ const tag = scratch
+ const payload = operand
+ loadConstantOrVariable2Reg(operand, tag, payload)
+ writeBarrier(tag, payload)
+ storei tag, TagOffset[base, index, 8]
+ storei payload, PayloadOffset[base, index, 8]
+ end)
.opPutByValNotContiguous:
bineq t2, ArrayStorageShape, .opPutByValSlow
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
index c9900b343..d8a293337 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
@@ -1025,7 +1025,9 @@ _llint_op_get_by_val:
sxi2q t1, t1
loadp JSObject::m_butterfly[t0], t3
andi IndexingShapeMask, t2
+ bieq t2, Int32Shape, .opGetByValIsContiguous
bineq t2, ContiguousShape, .opGetByValNotContiguous
+.opGetByValIsContiguous:
biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow
loadisFromInstruction(1, t0)
@@ -1034,6 +1036,16 @@ _llint_op_get_by_val:
jmp .opGetByValDone
.opGetByValNotContiguous:
+ bineq t2, DoubleShape, .opGetByValNotDouble
+ biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow
+ loadis 8[PB, PC, 8], t0
+ loadd [t3, t1, 8], ft0
+ bdnequn ft0, ft0, .opGetByValSlow
+ fd2q ft0, t2
+ subq tagTypeNumber, t2
+ jmp .opGetByValDone
+
+.opGetByValNotDouble:
subi ArrayStorageShape, t2
bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow
biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t3], .opGetByValSlow
@@ -1109,6 +1121,24 @@ _llint_op_get_by_pname:
dispatch(7)
+macro contiguousPutByVal(storeCallback)
+ biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .outOfBounds
+.storeResult:
+ loadisFromInstruction(3, t2)
+ storeCallback(t2, t1, [t0, t3, 8])
+ dispatch(5)
+
+.outOfBounds:
+ biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow
+ if VALUE_PROFILER
+ loadp 32[PB, PC, 8], t2
+ storeb 1, ArrayProfile::m_mayStoreToHole[t2]
+ end
+ addi 1, t3, t2
+ storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0]
+ jmp .storeResult
+end
+
_llint_op_put_by_val:
traceExecution()
loadisFromInstruction(1, t0)
@@ -1121,25 +1151,38 @@ _llint_op_put_by_val:
sxi2q t3, t3
loadp JSObject::m_butterfly[t1], t0
andi IndexingShapeMask, t2
- bineq t2, ContiguousShape, .opPutByValNotContiguous
-
- biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .opPutByValContiguousOutOfBounds
-.opPutByValContiguousStoreResult:
- loadisFromInstruction(3, t2)
- loadConstantOrVariable(t2, t1)
- writeBarrier(t1)
- storeq t1, [t0, t3, 8]
- dispatch(5)
+ bineq t2, Int32Shape, .opPutByValNotInt32
+ contiguousPutByVal(
+ macro (operand, scratch, address)
+ loadConstantOrVariable(operand, scratch)
+ bpb scratch, tagTypeNumber, .opPutByValSlow
+ storep scratch, address
+ end)
-.opPutByValContiguousOutOfBounds:
- biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow
- if VALUE_PROFILER
- loadpFromInstruction(4, t2)
- storeb 1, ArrayProfile::m_mayStoreToHole[t2]
- end
- addi 1, t3, t2
- storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0]
- jmp .opPutByValContiguousStoreResult
+.opPutByValNotInt32:
+ bineq t2, DoubleShape, .opPutByValNotDouble
+ contiguousPutByVal(
+ macro (operand, scratch, address)
+ loadConstantOrVariable(operand, scratch)
+ bqb scratch, tagTypeNumber, .notInt
+ ci2d scratch, ft0
+ jmp .ready
+ .notInt:
+ addp tagTypeNumber, scratch
+ fq2d scratch, ft0
+ bdnequn ft0, ft0, .opPutByValSlow
+ .ready:
+ stored ft0, address
+ end)
+
+.opPutByValNotDouble:
+ bineq t2, ContiguousShape, .opPutByValNotContiguous
+ contiguousPutByVal(
+ macro (operand, scratch, address)
+ loadConstantOrVariable(operand, scratch)
+ writeBarrier(scratch)
+ storep scratch, address
+ end)
.opPutByValNotContiguous:
bineq t2, ArrayStorageShape, .opPutByValSlow
diff --git a/Source/JavaScriptCore/offlineasm/x86.rb b/Source/JavaScriptCore/offlineasm/x86.rb
index 67cbd14b0..f78b43912 100644
--- a/Source/JavaScriptCore/offlineasm/x86.rb
+++ b/Source/JavaScriptCore/offlineasm/x86.rb
@@ -764,11 +764,16 @@ class Instruction
when "ci2d"
$asm.puts "cvtsi2sd #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:double)}"
when "bdeq"
- isUnordered = LocalLabel.unique("bdeq")
$asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
- $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
- $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}"
- isUnordered.lower("X86")
+ if operands[0] == operands[1]
+ # This is just a jump ordered, which is a jnp.
+ $asm.puts "jnp #{operands[2].asmLabel}"
+ else
+ isUnordered = LocalLabel.unique("bdeq")
+ $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
+ $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}"
+ isUnordered.lower("X86")
+ end
when "bdneq"
handleX86DoubleBranch("jne", :normal)
when "bdgt"
@@ -782,14 +787,19 @@ class Instruction
when "bdequn"
handleX86DoubleBranch("je", :normal)
when "bdnequn"
- isUnordered = LocalLabel.unique("bdnequn")
- isEqual = LocalLabel.unique("bdnequn")
$asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
- $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
- $asm.puts "je #{LabelReference.new(codeOrigin, isEqual).asmLabel}"
- isUnordered.lower("X86")
- $asm.puts "jmp #{operands[2].asmLabel}"
- isEqual.lower("X86")
+ if operands[0] == operands[1]
+ # This is just a jump unordered, which is a jp.
+ $asm.puts "jp #{operands[2].asmLabel}"
+ else
+ isUnordered = LocalLabel.unique("bdnequn")
+ isEqual = LocalLabel.unique("bdnequn")
+ $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
+ $asm.puts "je #{LabelReference.new(codeOrigin, isEqual).asmLabel}"
+ isUnordered.lower("X86")
+ $asm.puts "jmp #{operands[2].asmLabel}"
+ isEqual.lower("X86")
+ end
when "bdgtun"
handleX86DoubleBranch("jb", :reverse)
when "bdgtequn"
@@ -1115,7 +1125,7 @@ class Instruction
$asm.puts "movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
$asm.puts "movsd #{operands[0].x86Operand(:double)}, %xmm7"
$asm.puts "psrlq $32, %xmm7"
- $asm.puts "movsd %xmm7, #{operands[2].x86Operand(:int)}"
+ $asm.puts "movd %xmm7, #{operands[2].x86Operand(:int)}"
when "fq2d"
$asm.puts "movd #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}"
when "fd2q"
diff --git a/Source/JavaScriptCore/runtime/ArgList.h b/Source/JavaScriptCore/runtime/ArgList.h
index 29010b1ee..1fb1ce911 100644
--- a/Source/JavaScriptCore/runtime/ArgList.h
+++ b/Source/JavaScriptCore/runtime/ArgList.h
@@ -29,153 +29,153 @@
namespace JSC {
- class SlotVisitor;
-
- class MarkedArgumentBuffer {
- WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer);
- friend class JSGlobalData;
- friend class ArgList;
-
- private:
- static const size_t inlineCapacity = 8;
- typedef Vector<Register, inlineCapacity> VectorType;
- typedef HashSet<MarkedArgumentBuffer*> ListSet;
-
- public:
- // Constructor for a read-write list, to which you may append values.
- // FIXME: Remove all clients of this API, then remove this API.
- MarkedArgumentBuffer()
- : m_size(0)
- , m_capacity(inlineCapacity)
- , m_buffer(&m_inlineBuffer[m_capacity - 1])
- , m_markSet(0)
- {
- }
-
- ~MarkedArgumentBuffer()
- {
- if (m_markSet)
- m_markSet->remove(this);
-
- if (EncodedJSValue* base = mallocBase())
- delete [] base;
- }
-
- size_t size() const { return m_size; }
- bool isEmpty() const { return !m_size; }
-
- JSValue at(int i) const
- {
- if (i >= m_size)
- return jsUndefined();
-
- return JSValue::decode(slotFor(i));
- }
-
- void clear()
- {
- m_size = 0;
- }
-
- void append(JSValue v)
- {
- if (m_size >= m_capacity)
- return slowAppend(v);
-
- slotFor(m_size) = JSValue::encode(v);
- ++m_size;
- }
-
- void removeLast()
- {
- ASSERT(m_size);
- m_size--;
- }
-
- JSValue last()
- {
- ASSERT(m_size);
- return JSValue::decode(slotFor(m_size - 1));
- }
+class SlotVisitor;
+
+class MarkedArgumentBuffer {
+ WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer);
+ friend class JSGlobalData;
+ friend class ArgList;
+
+private:
+ static const size_t inlineCapacity = 8;
+ typedef Vector<Register, inlineCapacity> VectorType;
+ typedef HashSet<MarkedArgumentBuffer*> ListSet;
+
+public:
+ // Constructor for a read-write list, to which you may append values.
+ // FIXME: Remove all clients of this API, then remove this API.
+ MarkedArgumentBuffer()
+ : m_size(0)
+ , m_capacity(inlineCapacity)
+ , m_buffer(&m_inlineBuffer[m_capacity - 1])
+ , m_markSet(0)
+ {
+ }
+
+ ~MarkedArgumentBuffer()
+ {
+ if (m_markSet)
+ m_markSet->remove(this);
+
+ if (EncodedJSValue* base = mallocBase())
+ delete [] base;
+ }
+
+ size_t size() const { return m_size; }
+ bool isEmpty() const { return !m_size; }
+
+ JSValue at(int i) const
+ {
+ if (i >= m_size)
+ return jsUndefined();
+
+ return JSValue::decode(slotFor(i));
+ }
+
+ void clear()
+ {
+ m_size = 0;
+ }
+
+ void append(JSValue v)
+ {
+ if (m_size >= m_capacity)
+ return slowAppend(v);
+
+ slotFor(m_size) = JSValue::encode(v);
+ ++m_size;
+ }
+
+ void removeLast()
+ {
+ ASSERT(m_size);
+ m_size--;
+ }
+
+ JSValue last()
+ {
+ ASSERT(m_size);
+ return JSValue::decode(slotFor(m_size - 1));
+ }
- static void markLists(HeapRootVisitor&, ListSet&);
+ static void markLists(HeapRootVisitor&, ListSet&);
- private:
- JS_EXPORT_PRIVATE void slowAppend(JSValue);
+private:
+ JS_EXPORT_PRIVATE void slowAppend(JSValue);
- EncodedJSValue& slotFor(int item) const
- {
- return m_buffer[-item];
- }
+ EncodedJSValue& slotFor(int item) const
+ {
+ return m_buffer[-item];
+ }
- EncodedJSValue* mallocBase()
- {
- if (m_capacity == static_cast<int>(inlineCapacity))
- return 0;
- return &slotFor(m_capacity - 1);
- }
+ EncodedJSValue* mallocBase()
+ {
+ if (m_capacity == static_cast<int>(inlineCapacity))
+ return 0;
+ return &slotFor(m_capacity - 1);
+ }
- int m_size;
- int m_capacity;
- EncodedJSValue m_inlineBuffer[inlineCapacity];
- EncodedJSValue* m_buffer;
- ListSet* m_markSet;
-
- private:
- // Prohibits new / delete, which would break GC.
- void* operator new(size_t size)
- {
- return fastMalloc(size);
- }
- void operator delete(void* p)
- {
- fastFree(p);
- }
-
- void* operator new[](size_t);
- void operator delete[](void*);
-
- void* operator new(size_t, void*);
- void operator delete(void*, size_t);
- };
-
- class ArgList {
- friend class JIT;
- public:
- ArgList()
- : m_args(0)
- , m_argCount(0)
- {
- }
-
- ArgList(ExecState* exec)
- : m_args(reinterpret_cast<JSValue*>(&exec[CallFrame::argumentOffset(0)]))
- , m_argCount(exec->argumentCount())
- {
- }
-
- ArgList(const MarkedArgumentBuffer& args)
- : m_args(reinterpret_cast<JSValue*>(args.m_buffer))
- , m_argCount(args.size())
- {
- }
-
- JSValue at(int i) const
- {
- if (i >= m_argCount)
- return jsUndefined();
- return m_args[-i];
- }
-
- bool isEmpty() const { return !m_argCount; }
- size_t size() const { return m_argCount; }
+ int m_size;
+ int m_capacity;
+ EncodedJSValue m_inlineBuffer[inlineCapacity];
+ EncodedJSValue* m_buffer;
+ ListSet* m_markSet;
+
+private:
+ // Prohibits new / delete, which would break GC.
+ void* operator new(size_t size)
+ {
+ return fastMalloc(size);
+ }
+ void operator delete(void* p)
+ {
+ fastFree(p);
+ }
+
+ void* operator new[](size_t);
+ void operator delete[](void*);
+
+ void* operator new(size_t, void*);
+ void operator delete(void*, size_t);
+};
+
+class ArgList {
+ friend class JIT;
+public:
+ ArgList()
+ : m_args(0)
+ , m_argCount(0)
+ {
+ }
+
+ ArgList(ExecState* exec)
+ : m_args(reinterpret_cast<JSValue*>(&exec[CallFrame::argumentOffset(0)]))
+ , m_argCount(exec->argumentCount())
+ {
+ }
+
+ ArgList(const MarkedArgumentBuffer& args)
+ : m_args(reinterpret_cast<JSValue*>(args.m_buffer))
+ , m_argCount(args.size())
+ {
+ }
+
+ JSValue at(int i) const
+ {
+ if (i >= m_argCount)
+ return jsUndefined();
+ return m_args[-i];
+ }
+
+ bool isEmpty() const { return !m_argCount; }
+ size_t size() const { return m_argCount; }
- JS_EXPORT_PRIVATE void getSlice(int startIndex, ArgList& result) const;
+ JS_EXPORT_PRIVATE void getSlice(int startIndex, ArgList& result) const;
- private:
- JSValue* m_args;
- int m_argCount;
- };
+private:
+ JSValue* m_args;
+ int m_argCount;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h
index 7961d4bc8..8ae991422 100644
--- a/Source/JavaScriptCore/runtime/Arguments.h
+++ b/Source/JavaScriptCore/runtime/Arguments.h
@@ -34,246 +34,246 @@
namespace JSC {
- class Arguments : public JSDestructibleObject {
- friend class JIT;
- friend class DFG::SpeculativeJIT;
- public:
- typedef JSDestructibleObject Base;
-
- static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame)
- {
- Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
- arguments->finishCreation(callFrame);
- return arguments;
- }
-
- static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
- {
- Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
- arguments->finishCreation(callFrame, inlineCallFrame);
- return arguments;
- }
-
- enum { MaxArguments = 0x10000 };
-
- private:
- enum NoParametersType { NoParameters };
-
- Arguments(CallFrame*);
- Arguments(CallFrame*, NoParametersType);
-
- void tearOffForInlineCallFrame(JSGlobalData& globalData, Register*, InlineCallFrame*);
+class Arguments : public JSDestructibleObject {
+ friend class JIT;
+ friend class DFG::SpeculativeJIT;
+public:
+ typedef JSDestructibleObject Base;
- public:
- static const ClassInfo s_info;
-
- static void visitChildren(JSCell*, SlotVisitor&);
-
- void fillArgList(ExecState*, MarkedArgumentBuffer&);
-
- uint32_t length(ExecState* exec) const
- {
- if (UNLIKELY(m_overrodeLength))
- return get(exec, exec->propertyNames().length).toUInt32(exec);
- return m_numArguments;
- }
-
- void copyToArguments(ExecState*, CallFrame*, uint32_t length);
- void tearOff(CallFrame*);
- void tearOff(CallFrame*, InlineCallFrame*);
- bool isTornOff() const { return m_registerArray; }
- void didTearOffActivation(ExecState*, JSActivation*);
-
- static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
- }
-
- protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
-
- void finishCreation(CallFrame*);
- void finishCreation(CallFrame*, InlineCallFrame*);
-
- private:
- static void destroy(JSCell*);
- static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
- static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
- static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
- static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
- static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
- static bool deleteProperty(JSCell*, ExecState*, PropertyName);
- static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
- static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
- void createStrictModeCallerIfNecessary(ExecState*);
- void createStrictModeCalleeIfNecessary(ExecState*);
-
- bool isArgument(size_t);
- bool trySetArgument(JSGlobalData&, size_t argument, JSValue);
- JSValue tryGetArgument(size_t argument);
- bool isDeletedArgument(size_t);
- bool tryDeleteArgument(size_t);
- WriteBarrierBase<Unknown>& argument(size_t);
- void allocateSlowArguments();
-
- void init(CallFrame*);
-
- WriteBarrier<JSActivation> m_activation;
-
- unsigned m_numArguments;
-
- // We make these full byte booleans to make them easy to test from the JIT,
- // and because even if they were single-bit booleans we still wouldn't save
- // any space.
- bool m_overrodeLength;
- bool m_overrodeCallee;
- bool m_overrodeCaller;
- bool m_isStrictMode;
-
- WriteBarrierBase<Unknown>* m_registers;
- OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray;
-
- OwnArrayPtr<SlowArgument> m_slowArguments;
-
- WriteBarrier<JSFunction> m_callee;
- };
-
- Arguments* asArguments(JSValue);
-
- inline Arguments* asArguments(JSValue value)
+ static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame)
{
- ASSERT(asObject(value)->inherits(&Arguments::s_info));
- return static_cast<Arguments*>(asObject(value));
+ Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
+ arguments->finishCreation(callFrame);
+ return arguments;
}
-
- inline Arguments::Arguments(CallFrame* callFrame)
- : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+
+ static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
{
+ Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
+ arguments->finishCreation(callFrame, inlineCallFrame);
+ return arguments;
}
- inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
- : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
- {
- }
+ enum { MaxArguments = 0x10000 };
- inline void Arguments::allocateSlowArguments()
- {
- if (m_slowArguments)
- return;
- m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]);
- for (size_t i = 0; i < m_numArguments; ++i) {
- ASSERT(m_slowArguments[i].status == SlowArgument::Normal);
- m_slowArguments[i].index = CallFrame::argumentOffset(i);
- }
- }
+private:
+ enum NoParametersType { NoParameters };
+
+ Arguments(CallFrame*);
+ Arguments(CallFrame*, NoParametersType);
+
+ void tearOffForInlineCallFrame(JSGlobalData& globalData, Register*, InlineCallFrame*);
- inline bool Arguments::tryDeleteArgument(size_t argument)
- {
- if (!isArgument(argument))
- return false;
- allocateSlowArguments();
- m_slowArguments[argument].status = SlowArgument::Deleted;
- return true;
- }
+public:
+ static const ClassInfo s_info;
- inline bool Arguments::trySetArgument(JSGlobalData& globalData, size_t argument, JSValue value)
- {
- if (!isArgument(argument))
- return false;
- this->argument(argument).set(globalData, this, value);
- return true;
- }
+ static void visitChildren(JSCell*, SlotVisitor&);
- inline JSValue Arguments::tryGetArgument(size_t argument)
- {
- if (!isArgument(argument))
- return JSValue();
- return this->argument(argument).get();
- }
+ void fillArgList(ExecState*, MarkedArgumentBuffer&);
- inline bool Arguments::isDeletedArgument(size_t argument)
+ uint32_t length(ExecState* exec) const
{
- if (argument >= m_numArguments)
- return false;
- if (!m_slowArguments)
- return false;
- if (m_slowArguments[argument].status != SlowArgument::Deleted)
- return false;
- return true;
+ if (UNLIKELY(m_overrodeLength))
+ return get(exec, exec->propertyNames().length).toUInt32(exec);
+ return m_numArguments;
}
-
- inline bool Arguments::isArgument(size_t argument)
- {
- if (argument >= m_numArguments)
- return false;
- if (m_slowArguments && m_slowArguments[argument].status == SlowArgument::Deleted)
- return false;
- return true;
+
+ void copyToArguments(ExecState*, CallFrame*, uint32_t length);
+ void tearOff(CallFrame*);
+ void tearOff(CallFrame*, InlineCallFrame*);
+ bool isTornOff() const { return m_registerArray; }
+ void didTearOffActivation(ExecState*, JSActivation*);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
}
-
- inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument)
- {
- ASSERT(isArgument(argument));
- if (!m_slowArguments)
- return m_registers[CallFrame::argumentOffset(argument)];
-
- int index = m_slowArguments[argument].index;
- if (!m_activation || m_slowArguments[argument].status != SlowArgument::Captured)
- return m_registers[index];
-
- return m_activation->registerAt(index);
+
+protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
+
+ void finishCreation(CallFrame*);
+ void finishCreation(CallFrame*, InlineCallFrame*);
+
+private:
+ static void destroy(JSCell*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
+ static bool deleteProperty(JSCell*, ExecState*, PropertyName);
+ static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
+ static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
+ void createStrictModeCallerIfNecessary(ExecState*);
+ void createStrictModeCalleeIfNecessary(ExecState*);
+
+ bool isArgument(size_t);
+ bool trySetArgument(JSGlobalData&, size_t argument, JSValue);
+ JSValue tryGetArgument(size_t argument);
+ bool isDeletedArgument(size_t);
+ bool tryDeleteArgument(size_t);
+ WriteBarrierBase<Unknown>& argument(size_t);
+ void allocateSlowArguments();
+
+ void init(CallFrame*);
+
+ WriteBarrier<JSActivation> m_activation;
+
+ unsigned m_numArguments;
+
+ // We make these full byte booleans to make them easy to test from the JIT,
+ // and because even if they were single-bit booleans we still wouldn't save
+ // any space.
+ bool m_overrodeLength;
+ bool m_overrodeCallee;
+ bool m_overrodeCaller;
+ bool m_isStrictMode;
+
+ WriteBarrierBase<Unknown>* m_registers;
+ OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray;
+
+ OwnArrayPtr<SlowArgument> m_slowArguments;
+
+ WriteBarrier<JSFunction> m_callee;
+};
+
+Arguments* asArguments(JSValue);
+
+inline Arguments* asArguments(JSValue value)
+{
+ ASSERT(asObject(value)->inherits(&Arguments::s_info));
+ return static_cast<Arguments*>(asObject(value));
+}
+
+inline Arguments::Arguments(CallFrame* callFrame)
+ : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+{
+}
+
+inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
+ : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+{
+}
+
+inline void Arguments::allocateSlowArguments()
+{
+ if (m_slowArguments)
+ return;
+ m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]);
+ for (size_t i = 0; i < m_numArguments; ++i) {
+ ASSERT(m_slowArguments[i].status == SlowArgument::Normal);
+ m_slowArguments[i].index = CallFrame::argumentOffset(i);
}
-
- inline void Arguments::finishCreation(CallFrame* callFrame)
- {
- Base::finishCreation(callFrame->globalData());
- ASSERT(inherits(&s_info));
-
- JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
- m_numArguments = callFrame->argumentCount();
- m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers());
- m_callee.set(callFrame->globalData(), this, callee);
- m_overrodeLength = false;
- m_overrodeCallee = false;
- m_overrodeCaller = false;
- m_isStrictMode = callFrame->codeBlock()->isStrictMode();
-
- SharedSymbolTable* symbolTable = callFrame->codeBlock()->symbolTable();
- const SlowArgument* slowArguments = symbolTable->slowArguments();
- if (slowArguments) {
- allocateSlowArguments();
- size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount());
- for (size_t i = 0; i < count; ++i)
- m_slowArguments[i] = slowArguments[i];
- }
-
- // The bytecode generator omits op_tear_off_activation in cases of no
- // declared parameters, so we need to tear off immediately.
- if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
- tearOff(callFrame);
+}
+
+inline bool Arguments::tryDeleteArgument(size_t argument)
+{
+ if (!isArgument(argument))
+ return false;
+ allocateSlowArguments();
+ m_slowArguments[argument].status = SlowArgument::Deleted;
+ return true;
+}
+
+inline bool Arguments::trySetArgument(JSGlobalData& globalData, size_t argument, JSValue value)
+{
+ if (!isArgument(argument))
+ return false;
+ this->argument(argument).set(globalData, this, value);
+ return true;
+}
+
+inline JSValue Arguments::tryGetArgument(size_t argument)
+{
+ if (!isArgument(argument))
+ return JSValue();
+ return this->argument(argument).get();
+}
+
+inline bool Arguments::isDeletedArgument(size_t argument)
+{
+ if (argument >= m_numArguments)
+ return false;
+ if (!m_slowArguments)
+ return false;
+ if (m_slowArguments[argument].status != SlowArgument::Deleted)
+ return false;
+ return true;
+}
+
+inline bool Arguments::isArgument(size_t argument)
+{
+ if (argument >= m_numArguments)
+ return false;
+ if (m_slowArguments && m_slowArguments[argument].status == SlowArgument::Deleted)
+ return false;
+ return true;
+}
+
+inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument)
+{
+ ASSERT(isArgument(argument));
+ if (!m_slowArguments)
+ return m_registers[CallFrame::argumentOffset(argument)];
+
+ int index = m_slowArguments[argument].index;
+ if (!m_activation || m_slowArguments[argument].status != SlowArgument::Captured)
+ return m_registers[index];
+
+ return m_activation->registerAt(index);
+}
+
+inline void Arguments::finishCreation(CallFrame* callFrame)
+{
+ Base::finishCreation(callFrame->globalData());
+ ASSERT(inherits(&s_info));
+
+ JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
+ m_numArguments = callFrame->argumentCount();
+ m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers());
+ m_callee.set(callFrame->globalData(), this, callee);
+ m_overrodeLength = false;
+ m_overrodeCallee = false;
+ m_overrodeCaller = false;
+ m_isStrictMode = callFrame->codeBlock()->isStrictMode();
+
+ SharedSymbolTable* symbolTable = callFrame->codeBlock()->symbolTable();
+ const SlowArgument* slowArguments = symbolTable->slowArguments();
+ if (slowArguments) {
+ allocateSlowArguments();
+ size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount());
+ for (size_t i = 0; i < count; ++i)
+ m_slowArguments[i] = slowArguments[i];
}
- inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
- {
- Base::finishCreation(callFrame->globalData());
- ASSERT(inherits(&s_info));
-
- JSFunction* callee = inlineCallFrame->callee.get();
- m_numArguments = inlineCallFrame->arguments.size() - 1;
- m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset;
- m_callee.set(callFrame->globalData(), this, callee);
- m_overrodeLength = false;
- m_overrodeCallee = false;
- m_overrodeCaller = false;
- m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
- ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)->slowArguments());
-
- // The bytecode generator omits op_tear_off_activation in cases of no
- // declared parameters, so we need to tear off immediately.
- if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
- tearOff(callFrame, inlineCallFrame);
- }
+ // The bytecode generator omits op_tear_off_activation in cases of no
+ // declared parameters, so we need to tear off immediately.
+ if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
+ tearOff(callFrame);
+}
+
+inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
+{
+ Base::finishCreation(callFrame->globalData());
+ ASSERT(inherits(&s_info));
+
+ JSFunction* callee = inlineCallFrame->callee.get();
+ m_numArguments = inlineCallFrame->arguments.size() - 1;
+ m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset;
+ m_callee.set(callFrame->globalData(), this, callee);
+ m_overrodeLength = false;
+ m_overrodeCallee = false;
+ m_overrodeCaller = false;
+ m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
+ ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)->slowArguments());
+
+ // The bytecode generator omits op_tear_off_activation in cases of no
+ // declared parameters, so we need to tear off immediately.
+ if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
+ tearOff(callFrame, inlineCallFrame);
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
index 5c2cd7167..a3fce45f2 100644
--- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
@@ -25,8 +25,8 @@
#include "ArrayConstructor.h"
#include "ArrayPrototype.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
+#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "ExceptionHelpers.h"
#include "JSArray.h"
@@ -77,15 +77,15 @@ bool ArrayConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exe
// ------------------------------ Functions ---------------------------
-JSObject* constructArrayWithSizeQuirk(ExecState* exec, JSGlobalObject* globalObject, JSValue length)
+JSObject* constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length)
{
if (!length.isNumber())
- return constructArray(exec, globalObject, &length, 1);
+ return constructArray(exec, profile, globalObject, &length, 1);
uint32_t n = length.toUInt32(exec);
if (n != length.toNumber(exec))
return throwError(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer.")));
- return constructEmptyArray(exec, globalObject, n);
+ return constructEmptyArray(exec, profile, globalObject, n);
}
static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args)
@@ -94,10 +94,10 @@ static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgLi
// a single numeric argument denotes the array size (!)
if (args.size() == 1)
- return constructArrayWithSizeQuirk(exec, globalObject, args.at(0));
+ return constructArrayWithSizeQuirk(exec, 0, globalObject, args.at(0));
// otherwise the array is constructed with the arguments in it
- return constructArray(exec, globalObject, args);
+ return constructArray(exec, 0, globalObject, args);
}
static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec)
diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.h b/Source/JavaScriptCore/runtime/ArrayConstructor.h
index dcbf0a1b3..96860b0fc 100644
--- a/Source/JavaScriptCore/runtime/ArrayConstructor.h
+++ b/Source/JavaScriptCore/runtime/ArrayConstructor.h
@@ -25,42 +25,42 @@
namespace JSC {
- class ArrayPrototype;
- class JSArray;
+class ArrayPrototype;
+class JSArray;
- class ArrayConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
+class ArrayConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
- static ArrayConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ArrayPrototype* arrayPrototype)
- {
- ArrayConstructor* constructor = new (NotNull, allocateCell<ArrayConstructor>(*exec->heap())) ArrayConstructor(globalObject, structure);
- constructor->finishCreation(exec, arrayPrototype);
- return constructor;
- }
+ static ArrayConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ArrayPrototype* arrayPrototype)
+ {
+ ArrayConstructor* constructor = new (NotNull, allocateCell<ArrayConstructor>(*exec->heap())) ArrayConstructor(globalObject, structure);
+ constructor->finishCreation(exec, arrayPrototype);
+ return constructor;
+ }
- static const ClassInfo s_info;
+ static const ClassInfo s_info;
- static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
- }
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
- protected:
- void finishCreation(ExecState*, ArrayPrototype*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+protected:
+ void finishCreation(ExecState*, ArrayPrototype*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
- private:
- ArrayConstructor(JSGlobalObject*, Structure*);
- static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
+private:
+ ArrayConstructor(JSGlobalObject*, Structure*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
- static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
- };
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
- JSObject* constructArrayWithSizeQuirk(ExecState*, JSGlobalObject*, JSValue);
+JSObject* constructArrayWithSizeQuirk(ExecState*, ArrayAllocationProfile*, JSGlobalObject*, JSValue);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
index 6975dc778..cc847d8ff 100644
--- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
@@ -24,10 +24,10 @@
#include "config.h"
#include "ArrayPrototype.h"
-#include "ButterflyInlineMethods.h"
+#include "ButterflyInlines.h"
#include "CachedCall.h"
#include "CodeBlock.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "Interpreter.h"
#include "JIT.h"
#include "JSStringBuilder.h"
@@ -456,7 +456,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
{
JSValue thisValue = exec->hostThisValue();
- JSArray* arr = constructEmptyArray(exec);
+ JSArray* arr = constructEmptyArray(exec, 0);
unsigned n = 0;
JSValue curArg = thisValue.toObject(exec);
if (exec->hadException())
@@ -618,7 +618,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
return JSValue::encode(jsUndefined());
// We return a new array
- JSArray* resObj = constructEmptyArray(exec);
+ JSArray* resObj = constructEmptyArray(exec, 0);
JSValue result = resObj;
unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
@@ -733,7 +733,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
return JSValue::encode(jsUndefined());
if (!exec->argumentCount())
- return JSValue::encode(constructEmptyArray(exec));
+ return JSValue::encode(constructEmptyArray(exec, 0));
unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
@@ -748,7 +748,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
deleteCount = static_cast<unsigned>(deleteDouble);
}
- JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), deleteCount);
+ JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount);
if (!resObj)
return JSValue::encode(throwOutOfMemoryError(exec));
@@ -820,7 +820,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
return throwVMTypeError(exec);
JSValue applyThis = exec->argument(1);
- JSArray* resultArray = constructEmptyArray(exec);
+ JSArray* resultArray = constructEmptyArray(exec, 0);
unsigned filterIndex = 0;
unsigned k = 0;
@@ -880,7 +880,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
JSValue applyThis = exec->argument(1);
- JSArray* resultArray = constructEmptyArray(exec, length);
+ JSArray* resultArray = constructEmptyArray(exec, 0, length);
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(thisObj)) {
JSFunction* f = jsCast<JSFunction*>(function);
diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.h b/Source/JavaScriptCore/runtime/ArrayPrototype.h
index b33021121..2b83d39b7 100644
--- a/Source/JavaScriptCore/runtime/ArrayPrototype.h
+++ b/Source/JavaScriptCore/runtime/ArrayPrototype.h
@@ -26,28 +26,28 @@
namespace JSC {
- class ArrayPrototype : public JSArray {
- private:
- ArrayPrototype(JSGlobalObject*, Structure*, Butterfly*);
+class ArrayPrototype : public JSArray {
+private:
+ ArrayPrototype(JSGlobalObject*, Structure*, Butterfly*);
- public:
- typedef JSArray Base;
+public:
+ typedef JSArray Base;
- static ArrayPrototype* create(ExecState*, JSGlobalObject*, Structure*);
+ static ArrayPrototype* create(ExecState*, JSGlobalObject*, Structure*);
- static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
- static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
- static const ClassInfo s_info;
+ static const ClassInfo s_info;
- static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayWithArrayStorage);
- }
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayWithArrayStorage);
+ }
- protected:
- void finishCreation(JSGlobalObject*);
- };
+protected:
+ void finishCreation(JSGlobalObject*);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h
index cb93aea8a..4b8d53f7e 100644
--- a/Source/JavaScriptCore/runtime/Butterfly.h
+++ b/Source/JavaScriptCore/runtime/Butterfly.h
@@ -88,12 +88,18 @@ public:
template<typename T>
T* indexingPayload() { return reinterpret_cast<T*>(this); }
ArrayStorage* arrayStorage() { return indexingPayload<ArrayStorage>(); }
+ WriteBarrier<Unknown>* contiguousInt32() { return indexingPayload<WriteBarrier<Unknown> >(); }
+ double* contiguousDouble() { return indexingPayload<double>(); }
WriteBarrier<Unknown>* contiguous() { return indexingPayload<WriteBarrier<Unknown> >(); }
static Butterfly* fromContiguous(WriteBarrier<Unknown>* contiguous)
{
return reinterpret_cast<Butterfly*>(contiguous);
}
+ static Butterfly* fromContiguous(double* contiguous)
+ {
+ return reinterpret_cast<Butterfly*>(contiguous);
+ }
static ptrdiff_t offsetOfPropertyStorage() { return -static_cast<ptrdiff_t>(sizeof(IndexingHeader)); }
static int indexOfPropertyStorage()
diff --git a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h b/Source/JavaScriptCore/runtime/ButterflyInlines.h
index 86a836bef..9167497a4 100644
--- a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h
+++ b/Source/JavaScriptCore/runtime/ButterflyInlines.h
@@ -23,12 +23,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ButterflyInlineMethods_h
-#define ButterflyInlineMethods_h
+#ifndef ButterflyInlines_h
+#define ButterflyInlines_h
#include "ArrayStorage.h"
#include "Butterfly.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "CopyVisitor.h"
#include "JSGlobalData.h"
#include "Structure.h"
@@ -61,8 +61,9 @@ inline Butterfly* Butterfly::create(JSGlobalData& globalData, Structure* structu
inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
{
+ size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
Butterfly* result = fromBase(
- visitor.allocateNewSpace(totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)),
+ visitor.allocateNewSpace(size),
preCapacity, propertyCapacity);
return result;
}
@@ -175,5 +176,5 @@ inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots)
} // namespace JSC
-#endif // ButterflyInlineMethods_h
+#endif // ButterflyInlines_h
diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp
index 4de760e49..068919528 100644
--- a/Source/JavaScriptCore/runtime/CodeCache.cpp
+++ b/Source/JavaScriptCore/runtime/CodeCache.cpp
@@ -36,7 +36,6 @@
namespace JSC {
CodeCache::CodeCache()
- : m_randomGenerator(static_cast<uint32_t>(randomNumber() * UINT32_MAX))
{
}
@@ -67,9 +66,9 @@ UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, Executa
CodeBlockKey key = makeCodeBlockKey(source, CacheTypes<UnlinkedCodeBlockType>::codeType, strictness);
bool storeInCache = false;
if (debuggerMode == DebuggerOff && profilerMode == ProfilerOff) {
- CodeBlockIndicesMap::iterator result = m_cachedCodeBlockIndices.find(key);
- if (result != m_cachedCodeBlockIndices.end()) {
- UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(m_cachedCodeBlocks[result->value].second.get());
+ const Strong<UnlinkedCodeBlock>* result = m_cachedCodeBlocks.find(key);
+ if (result) {
+ UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(result->get());
unsigned firstLine = source.firstLine() + unlinkedCode->firstLine();
executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount());
return unlinkedCode;
@@ -91,14 +90,8 @@ UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, Executa
if (error.m_type != ParserError::ErrorNone)
return 0;
- if (storeInCache) {
- size_t index = m_randomGenerator.getUint32() % kMaxCodeBlockEntries;
- if (m_cachedCodeBlocks[index].second)
- m_cachedCodeBlockIndices.remove(m_cachedCodeBlocks[index].first);
- m_cachedCodeBlockIndices.set(key, index);
- m_cachedCodeBlocks[index].second.set(globalData, unlinkedCode);
- m_cachedCodeBlocks[index].first = key;
- }
+ if (storeInCache)
+ m_cachedCodeBlocks.add(key, Strong<UnlinkedCodeBlock>(globalData, unlinkedCode));
return unlinkedCode;
}
@@ -133,6 +126,7 @@ UnlinkedFunctionCodeBlock* CodeCache::generateFunctionCodeBlock(JSGlobalData& gl
body->destroyData();
if (error.m_type != ParserError::ErrorNone)
return 0;
+ m_cachedFunctionCode.add(result, Strong<UnlinkedFunctionCodeBlock>(globalData, result));
return result;
}
@@ -149,9 +143,9 @@ CodeCache::GlobalFunctionKey CodeCache::makeGlobalFunctionKey(const SourceCode&
UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, ParserError& error)
{
GlobalFunctionKey key = makeGlobalFunctionKey(source, name.string());
- GlobalFunctionIndicesMap::iterator result = m_cachedGlobalFunctionIndices.find(key);
- if (result != m_cachedGlobalFunctionIndices.end())
- return m_cachedGlobalFunctions[result->value].second.get();
+ const Strong<UnlinkedFunctionExecutable>* result = m_cachedGlobalFunctions.find(key);
+ if (result)
+ return result->get();
RefPtr<ProgramNode> program = parse<ProgramNode>(&globalData, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error);
if (!program) {
@@ -173,14 +167,13 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlo
UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&globalData, source, body);
functionExecutable->m_nameValue.set(globalData, functionExecutable, jsString(&globalData, name.string()));
- size_t index = m_randomGenerator.getUint32() % kMaxGlobalFunctionEntries;
- if (m_cachedGlobalFunctions[index].second)
- m_cachedGlobalFunctionIndices.remove(m_cachedGlobalFunctions[index].first);
- m_cachedGlobalFunctionIndices.set(key, index);
- m_cachedGlobalFunctions[index].second.set(globalData, functionExecutable);
- m_cachedGlobalFunctions[index].first = key;
-
+ m_cachedGlobalFunctions.add(key, Strong<UnlinkedFunctionExecutable>(globalData, functionExecutable));
return functionExecutable;
}
+void CodeCache::usedFunctionCode(JSGlobalData& globalData, UnlinkedFunctionCodeBlock* codeBlock)
+{
+ m_cachedFunctionCode.add(codeBlock, Strong<UnlinkedFunctionCodeBlock>(globalData, codeBlock));
+}
+
}
diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h
index 4d4617189..740aaa6df 100644
--- a/Source/JavaScriptCore/runtime/CodeCache.h
+++ b/Source/JavaScriptCore/runtime/CodeCache.h
@@ -34,6 +34,7 @@
#include <wtf/FixedArray.h>
#include <wtf/Forward.h>
#include <wtf/PassOwnPtr.h>
+#include <wtf/RandomNumber.h>
#include <wtf/text/WTFString.h>
namespace JSC {
@@ -51,6 +52,41 @@ struct ParserError;
class SourceCode;
class SourceProvider;
+template <typename KeyType, typename EntryType, int CacheSize> class Thingy {
+ typedef typename HashMap<KeyType, unsigned>::iterator iterator;
+public:
+ Thingy()
+ : m_randomGenerator((static_cast<uint32_t>(randomNumber() * UINT32_MAX)))
+ {
+ }
+ const EntryType* find(const KeyType& key)
+ {
+ iterator result = m_map.find(key);
+ if (result == m_map.end())
+ return 0;
+ return &m_data[result->value].second;
+ }
+ void add(const KeyType& key, const EntryType& value)
+ {
+ iterator result = m_map.find(key);
+ if (result != m_map.end()) {
+ m_data[result->value].second = value;
+ return;
+ }
+ size_t newIndex = m_randomGenerator.getUint32() % CacheSize;
+ if (m_data[newIndex].second)
+ m_map.remove(m_data[newIndex].first);
+ m_map.add(key, newIndex);
+ m_data[newIndex].first = key;
+ m_data[newIndex].second = value;
+ ASSERT(m_map.size() <= CacheSize);
+ }
+private:
+ HashMap<KeyType, unsigned> m_map;
+ FixedArray<std::pair<KeyType, EntryType>, CacheSize> m_data;
+ WeakRandom m_randomGenerator;
+};
+
class CodeCache {
public:
static PassOwnPtr<CodeCache> create() { return adoptPtr(new CodeCache); }
@@ -59,13 +95,12 @@ public:
UnlinkedEvalCodeBlock* getEvalCodeBlock(JSGlobalData&, EvalExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
UnlinkedFunctionCodeBlock* getFunctionCodeBlock(JSGlobalData&, UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&);
UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(JSGlobalData&, const Identifier&, const SourceCode&, ParserError&);
+ void usedFunctionCode(JSGlobalData&, UnlinkedFunctionCodeBlock*);
~CodeCache();
enum CodeType { EvalType, ProgramType, FunctionType };
typedef std::pair<String, unsigned> CodeBlockKey;
- typedef HashMap<CodeBlockKey, unsigned> CodeBlockIndicesMap;
typedef std::pair<String, String> GlobalFunctionKey;
- typedef HashMap<GlobalFunctionKey, unsigned> GlobalFunctionIndicesMap;
private:
CodeCache();
@@ -74,18 +109,17 @@ private:
template <class UnlinkedCodeBlockType, class ExecutableType> inline UnlinkedCodeBlockType* getCodeBlock(JSGlobalData&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
CodeBlockKey makeCodeBlockKey(const SourceCode&, CodeType, JSParserStrictness);
- CodeBlockIndicesMap m_cachedCodeBlockIndices;
GlobalFunctionKey makeGlobalFunctionKey(const SourceCode&, const String&);
- GlobalFunctionIndicesMap m_cachedGlobalFunctionIndices;
enum {
kMaxCodeBlockEntries = 1024,
- kMaxGlobalFunctionEntries = 1024
+ kMaxGlobalFunctionEntries = 1024,
+ kMaxFunctionCodeBlocks = 1024
};
- FixedArray<std::pair<CodeBlockKey, Strong<UnlinkedCodeBlock> >, kMaxCodeBlockEntries> m_cachedCodeBlocks;
- FixedArray<std::pair<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable> >, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions;
- WeakRandom m_randomGenerator;
+ Thingy<CodeBlockKey, Strong<UnlinkedCodeBlock>, kMaxCodeBlockEntries> m_cachedCodeBlocks;
+ Thingy<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable>, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions;
+ Thingy<UnlinkedFunctionCodeBlock*, Strong<UnlinkedFunctionCodeBlock>, kMaxFunctionCodeBlocks> m_cachedFunctionCode;
};
}
diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp
index 20a2e2acb..49a0e256d 100644
--- a/Source/JavaScriptCore/runtime/Executable.cpp
+++ b/Source/JavaScriptCore/runtime/Executable.cpp
@@ -620,18 +620,17 @@ void FunctionExecutable::clearCodeIfNotCompiling()
clearCode();
}
-void FunctionExecutable::clearUnlinkedCodeIfNotCompiling()
+void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling()
{
if (isCompiling())
return;
- m_unlinkedExecutable->clearCode();
+ m_unlinkedExecutable->clearCodeForRecompilation();
}
void FunctionExecutable::clearCode()
{
m_codeBlockForCall.clear();
m_codeBlockForConstruct.clear();
- m_unlinkedExecutable->clearCode();
Base::clearCode();
}
diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h
index 74b4add75..98471b85b 100644
--- a/Source/JavaScriptCore/runtime/Executable.h
+++ b/Source/JavaScriptCore/runtime/Executable.h
@@ -704,7 +704,7 @@ namespace JSC {
SharedSymbolTable* symbolTable(CodeSpecializationKind kind) const { return m_unlinkedExecutable->symbolTable(kind); }
void clearCodeIfNotCompiling();
- void clearUnlinkedCodeIfNotCompiling();
+ void clearUnlinkedCodeForRecompilationIfNotCompiling();
static void visitChildren(JSCell*, SlotVisitor&);
static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
{
diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
index a4b2202c1..8e4390b1b 100644
--- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
@@ -186,7 +186,7 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec)
// Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
size_t numBoundArgs = exec->argumentCount() > 1 ? exec->argumentCount() - 1 : 0;
- JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructure(), numBoundArgs);
+ JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), numBoundArgs);
if (!boundArgs)
return JSValue::encode(throwOutOfMemoryError(exec));
diff --git a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h b/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h
index 22785ce24..cfad1c8c2 100644
--- a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h
+++ b/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h
@@ -23,8 +23,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef IndexingHeaderInlineMethods_h
-#define IndexingHeaderInlineMethods_h
+#ifndef IndexingHeaderInlines_h
+#define IndexingHeaderInlines_h
#include "ArrayStorage.h"
#include "IndexingHeader.h"
@@ -43,6 +43,9 @@ inline size_t IndexingHeader::preCapacity(Structure* structure)
inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure)
{
switch (structure->indexingType()) {
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return vectorLength() * sizeof(EncodedJSValue);
@@ -57,5 +60,5 @@ inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure)
} // namespace JSC
-#endif // IndexingHeaderInlineMethods_h
+#endif // IndexingHeaderInlines_h
diff --git a/Source/JavaScriptCore/runtime/IndexingType.cpp b/Source/JavaScriptCore/runtime/IndexingType.cpp
index 7261847a2..dc2733ad1 100644
--- a/Source/JavaScriptCore/runtime/IndexingType.cpp
+++ b/Source/JavaScriptCore/runtime/IndexingType.cpp
@@ -31,6 +31,46 @@
namespace JSC {
+IndexingType leastUpperBoundOfIndexingTypes(IndexingType a, IndexingType b)
+{
+ // It doesn't make sense to LUB something that is an array with something that isn't.
+ ASSERT((a & IsArray) == (b & IsArray));
+
+ // Boy, this sure is easy right now.
+ return std::max(a, b);
+}
+
+IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType indexingType, SpeculatedType type)
+{
+ if (!type)
+ return indexingType;
+ switch (indexingType) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ if (isInt32Speculation(type))
+ return (indexingType & ~IndexingShapeMask) | Int32Shape;
+ if (isNumberSpeculation(type))
+ return (indexingType & ~IndexingShapeMask) | DoubleShape;
+ return (indexingType & ~IndexingShapeMask) | ContiguousShape;
+ case ALL_DOUBLE_INDEXING_TYPES:
+ if (isNumberSpeculation(type))
+ return indexingType;
+ return (indexingType & ~IndexingShapeMask) | ContiguousShape;
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return indexingType;
+ default:
+ CRASH();
+ return 0;
+ }
+}
+
+IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType indexingType, JSValue value)
+{
+ return leastUpperBoundOfIndexingTypeAndType(indexingType, speculationFromValue(value));
+}
+
const char* indexingTypeToString(IndexingType indexingType)
{
static char result[128];
@@ -39,6 +79,12 @@ const char* indexingTypeToString(IndexingType indexingType)
case NonArray:
basicName = "NonArray";
break;
+ case NonArrayWithInt32:
+ basicName = "NonArrayWithInt32";
+ break;
+ case NonArrayWithDouble:
+ basicName = "NonArrayWithDouble";
+ break;
case NonArrayWithContiguous:
basicName = "NonArrayWithContiguous";
break;
@@ -51,6 +97,15 @@ const char* indexingTypeToString(IndexingType indexingType)
case ArrayClass:
basicName = "ArrayClass";
break;
+ case ArrayWithUndecided:
+ basicName = "ArrayWithUndecided";
+ break;
+ case ArrayWithInt32:
+ basicName = "ArrayWithInt32";
+ break;
+ case ArrayWithDouble:
+ basicName = "ArrayWithDouble";
+ break;
case ArrayWithContiguous:
basicName = "ArrayWithContiguous";
break;
diff --git a/Source/JavaScriptCore/runtime/IndexingType.h b/Source/JavaScriptCore/runtime/IndexingType.h
index 4bbe3cfa0..ab253be1e 100644
--- a/Source/JavaScriptCore/runtime/IndexingType.h
+++ b/Source/JavaScriptCore/runtime/IndexingType.h
@@ -26,6 +26,7 @@
#ifndef IndexingType_h
#define IndexingType_h
+#include "SpeculatedType.h"
#include <wtf/StdLibExtras.h>
namespace JSC {
@@ -37,21 +38,32 @@ static const IndexingType IsArray = 1;
// The shape of the indexed property storage.
static const IndexingType IndexingShapeMask = 30;
-static const IndexingType NoIndexingShape = 0;
+static const IndexingType NoIndexingShape = 0;
+static const IndexingType UndecidedShape = 2; // Only useful for arrays.
+static const IndexingType Int32Shape = 20;
+static const IndexingType DoubleShape = 22;
static const IndexingType ContiguousShape = 26;
static const IndexingType ArrayStorageShape = 28;
static const IndexingType SlowPutArrayStorageShape = 30;
+static const IndexingType IndexingShapeShift = 1;
+static const IndexingType NumberOfIndexingShapes = 16;
+
// Additional flags for tracking the history of the type. These are usually
// masked off unless you ask for them directly.
static const IndexingType MayHaveIndexedAccessors = 32;
// List of acceptable array types.
static const IndexingType NonArray = 0;
+static const IndexingType NonArrayWithInt32 = Int32Shape;
+static const IndexingType NonArrayWithDouble = DoubleShape;
static const IndexingType NonArrayWithContiguous = ContiguousShape;
static const IndexingType NonArrayWithArrayStorage = ArrayStorageShape;
static const IndexingType NonArrayWithSlowPutArrayStorage = SlowPutArrayStorageShape;
static const IndexingType ArrayClass = IsArray; // I'd want to call this "Array" but this would lead to disastrous namespace pollution.
+static const IndexingType ArrayWithUndecided = IsArray | UndecidedShape;
+static const IndexingType ArrayWithInt32 = IsArray | Int32Shape;
+static const IndexingType ArrayWithDouble = IsArray | DoubleShape;
static const IndexingType ArrayWithContiguous = IsArray | ContiguousShape;
static const IndexingType ArrayWithArrayStorage = IsArray | ArrayStorageShape;
static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArrayStorageShape;
@@ -60,6 +72,17 @@ static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArr
NonArray: \
case ArrayClass
+#define ALL_UNDECIDED_INDEXING_TYPES \
+ ArrayWithUndecided
+
+#define ALL_INT32_INDEXING_TYPES \
+ NonArrayWithInt32: \
+ case ArrayWithInt32
+
+#define ALL_DOUBLE_INDEXING_TYPES \
+ NonArrayWithDouble: \
+ case ArrayWithDouble
+
#define ALL_CONTIGUOUS_INDEXING_TYPES \
NonArrayWithContiguous: \
case ArrayWithContiguous
@@ -83,6 +106,21 @@ static inline bool hasIndexingHeader(IndexingType type)
return hasIndexedProperties(type);
}
+static inline bool hasUndecided(IndexingType indexingType)
+{
+ return (indexingType & IndexingShapeMask) == UndecidedShape;
+}
+
+static inline bool hasInt32(IndexingType indexingType)
+{
+ return (indexingType & IndexingShapeMask) == Int32Shape;
+}
+
+static inline bool hasDouble(IndexingType indexingType)
+{
+ return (indexingType & IndexingShapeMask) == DoubleShape;
+}
+
static inline bool hasContiguous(IndexingType indexingType)
{
return (indexingType & IndexingShapeMask) == ContiguousShape;
@@ -105,6 +143,12 @@ static inline bool shouldUseSlowPut(IndexingType indexingType)
return (indexingType & IndexingShapeMask) == SlowPutArrayStorageShape;
}
+// Return an indexing type that can handle all of the elements of both indexing types.
+IndexingType leastUpperBoundOfIndexingTypes(IndexingType, IndexingType);
+
+IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType, SpeculatedType);
+IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType, JSValue);
+
const char* indexingTypeToString(IndexingType);
// Mask of all possible types.
diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h
index fc6336463..b8f5621af 100644
--- a/Source/JavaScriptCore/runtime/JSActivation.h
+++ b/Source/JavaScriptCore/runtime/JSActivation.h
@@ -30,7 +30,7 @@
#define JSActivation_h
#include "CodeBlock.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "JSVariableObject.h"
#include "Nodes.h"
#include "SymbolTable.h"
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
index d1ece1a36..4ba5cc2bd 100644
--- a/Source/JavaScriptCore/runtime/JSArray.cpp
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -24,14 +24,14 @@
#include "JSArray.h"
#include "ArrayPrototype.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpace.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
#include "CachedCall.h"
+#include "CopiedSpace.h"
+#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "Executable.h"
#include "GetterSetter.h"
-#include "IndexingHeaderInlineMethods.h"
+#include "IndexingHeaderInlines.h"
#include "PropertyNameArray.h"
#include "Reject.h"
#include <wtf/AVLTree.h>
@@ -410,25 +410,33 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
exec, newLength, throwException,
convertContiguousToArrayStorage(exec->globalData()));
}
- createInitialContiguous(exec->globalData(), newLength);
+ createInitialUndecided(exec->globalData(), newLength);
return true;
+ case ArrayWithUndecided:
+ case ArrayWithInt32:
+ case ArrayWithDouble:
case ArrayWithContiguous:
if (newLength == m_butterfly->publicLength())
return true;
if (newLength >= MAX_ARRAY_INDEX // This case ensures that we can do fast push.
|| (newLength >= MIN_SPARSE_ARRAY_INDEX
- && !isDenseEnoughForVector(newLength, countElementsInContiguous(m_butterfly)))) {
+ && !isDenseEnoughForVector(newLength, countElements()))) {
return setLengthWithArrayStorage(
exec, newLength, throwException,
- convertContiguousToArrayStorage(exec->globalData()));
+ ensureArrayStorage(exec->globalData()));
}
if (newLength > m_butterfly->publicLength()) {
- ensureContiguousLength(exec->globalData(), newLength);
+ ensureLength(exec->globalData(), newLength);
return true;
}
- for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
- m_butterfly->contiguous()[i].clear();
+ if (structure()->indexingType() == ArrayWithDouble) {
+ for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
+ m_butterfly->contiguousDouble()[i] = QNaN;
+ } else {
+ for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
+ m_butterfly->contiguous()[i].clear();
+ }
m_butterfly->setPublicLength(newLength);
return true;
@@ -448,6 +456,13 @@ JSValue JSArray::pop(ExecState* exec)
case ArrayClass:
return jsUndefined();
+ case ArrayWithUndecided:
+ if (!m_butterfly->publicLength())
+ return jsUndefined();
+ // We have nothing but holes. So, drop down to the slow version.
+ break;
+
+ case ArrayWithInt32:
case ArrayWithContiguous: {
unsigned length = m_butterfly->publicLength();
@@ -464,6 +479,22 @@ JSValue JSArray::pop(ExecState* exec)
break;
}
+ case ArrayWithDouble: {
+ unsigned length = m_butterfly->publicLength();
+
+ if (!length--)
+ return jsUndefined();
+
+ ASSERT(length < m_butterfly->vectorLength());
+ double value = m_butterfly->contiguousDouble()[length];
+ if (value == value) {
+ m_butterfly->contiguousDouble()[length] = QNaN;
+ m_butterfly->setPublicLength(length);
+ return JSValue(JSValue::EncodeAsDouble, value);
+ }
+ break;
+ }
+
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
@@ -518,10 +549,42 @@ void JSArray::push(ExecState* exec, JSValue value)
{
switch (structure()->indexingType()) {
case ArrayClass: {
- putByIndexBeyondVectorLengthWithArrayStorage(exec, 0, value, true, createInitialArrayStorage(exec->globalData()));
- break;
+ createInitialUndecided(exec->globalData(), 0);
+ // Fall through.
+ }
+
+ case ArrayWithUndecided: {
+ convertUndecidedForValue(exec->globalData(), value);
+ push(exec, value);
+ return;
}
+ case ArrayWithInt32: {
+ if (!value.isInt32()) {
+ convertInt32ForValue(exec->globalData(), value);
+ push(exec, value);
+ return;
+ }
+
+ unsigned length = m_butterfly->publicLength();
+ ASSERT(length <= m_butterfly->vectorLength());
+ if (length < m_butterfly->vectorLength()) {
+ m_butterfly->contiguousInt32()[length].setWithoutWriteBarrier(value);
+ m_butterfly->setPublicLength(length + 1);
+ return;
+ }
+
+ if (length > MAX_ARRAY_INDEX) {
+ methodTable()->putByIndex(this, exec, length, value, true);
+ if (!exec->hadException())
+ throwError(exec, createRangeError(exec, "Invalid array length"));
+ return;
+ }
+
+ putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, length, value);
+ return;
+ }
+
case ArrayWithContiguous: {
unsigned length = m_butterfly->publicLength();
ASSERT(length <= m_butterfly->vectorLength());
@@ -538,10 +601,42 @@ void JSArray::push(ExecState* exec, JSValue value)
return;
}
- putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, length, value);
+ putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, length, value);
return;
}
+ case ArrayWithDouble: {
+ if (!value.isNumber()) {
+ convertDoubleToContiguous(exec->globalData());
+ push(exec, value);
+ return;
+ }
+ double valueAsDouble = value.asNumber();
+ if (valueAsDouble != valueAsDouble) {
+ convertDoubleToContiguous(exec->globalData());
+ push(exec, value);
+ return;
+ }
+
+ unsigned length = m_butterfly->publicLength();
+ ASSERT(length <= m_butterfly->vectorLength());
+ if (length < m_butterfly->vectorLength()) {
+ m_butterfly->contiguousDouble()[length] = valueAsDouble;
+ m_butterfly->setPublicLength(length + 1);
+ return;
+ }
+
+ if (length > MAX_ARRAY_INDEX) {
+ methodTable()->putByIndex(this, exec, length, value, true);
+ if (!exec->hadException())
+ throwError(exec, createRangeError(exec, "Invalid array length"));
+ return;
+ }
+
+ putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, length, value);
+ break;
+ }
+
case ArrayWithSlowPutArrayStorage: {
unsigned oldLength = length();
if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true)) {
@@ -647,6 +742,11 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
case ArrayClass:
return true;
+ case ArrayWithUndecided:
+ // Don't handle this because it's confusing and it shouldn't come up.
+ return false;
+
+ case ArrayWithInt32:
case ArrayWithContiguous: {
unsigned oldLength = m_butterfly->publicLength();
ASSERT(count <= oldLength);
@@ -654,7 +754,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
// We may have to walk the entire array to do the shift. We're willing to do
// so only if it's not horribly slow.
if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
- return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+ return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
unsigned end = oldLength - count;
for (unsigned i = startIndex; i < end; ++i) {
@@ -668,7 +768,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
// about holes (at least for now), but it can detect them quickly. So
// we convert to array storage and then allow the array storage path to
// figure it out.
- return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+ return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
}
// No need for a barrier since we're just moving data around in the same vector.
// This is in line with our standing assumption that we won't have a deletion
@@ -682,6 +782,41 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
return true;
}
+ case ArrayWithDouble: {
+ unsigned oldLength = m_butterfly->publicLength();
+ ASSERT(count <= oldLength);
+
+ // We may have to walk the entire array to do the shift. We're willing to do
+ // so only if it's not horribly slow.
+ if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
+ return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
+
+ unsigned end = oldLength - count;
+ for (unsigned i = startIndex; i < end; ++i) {
+ // Storing to a hole is fine since we're still having a good time. But reading
+ // from a hole is totally not fine, since we might have to read from the proto
+ // chain.
+ double v = m_butterfly->contiguousDouble()[i + count];
+ if (UNLIKELY(v != v)) {
+ // The purpose of this path is to ensure that we don't make the same
+ // mistake in the future: shiftCountWithArrayStorage() can't do anything
+ // about holes (at least for now), but it can detect them quickly. So
+ // we convert to array storage and then allow the array storage path to
+ // figure it out.
+ return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
+ }
+ // No need for a barrier since we're just moving data around in the same vector.
+ // This is in line with our standing assumption that we won't have a deletion
+ // barrier.
+ m_butterfly->contiguousDouble()[i] = v;
+ }
+ for (unsigned i = end; i < oldLength; ++i)
+ m_butterfly->contiguousDouble()[i] = QNaN;
+
+ m_butterfly->setPublicLength(oldLength - count);
+ return true;
+ }
+
case ArrayWithArrayStorage:
case ArrayWithSlowPutArrayStorage:
return shiftCountWithArrayStorage(startIndex, count, arrayStorage());
@@ -740,23 +875,25 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
{
switch (structure()->indexingType()) {
case ArrayClass:
+ case ArrayWithUndecided:
// We could handle this. But it shouldn't ever come up, so we won't.
return false;
-
+
+ case ArrayWithInt32:
case ArrayWithContiguous: {
unsigned oldLength = m_butterfly->publicLength();
// We may have to walk the entire array to do the unshift. We're willing to do so
// only if it's not horribly slow.
if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX)
- return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+ return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
- ensureContiguousLength(exec->globalData(), oldLength + count);
+ ensureLength(exec->globalData(), oldLength + count);
for (unsigned i = oldLength; i-- > startIndex;) {
JSValue v = m_butterfly->contiguous()[i].get();
if (UNLIKELY(!v))
- return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+ return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v);
}
@@ -768,6 +905,31 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
return true;
}
+ case ArrayWithDouble: {
+ unsigned oldLength = m_butterfly->publicLength();
+
+ // We may have to walk the entire array to do the unshift. We're willing to do so
+ // only if it's not horribly slow.
+ if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX)
+ return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
+
+ ensureLength(exec->globalData(), oldLength + count);
+
+ for (unsigned i = oldLength; i-- > startIndex;) {
+ double v = m_butterfly->contiguousDouble()[i];
+ if (UNLIKELY(v != v))
+ return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
+ m_butterfly->contiguousDouble()[i + count] = v;
+ }
+
+ // NOTE: we're leaving being garbage in the part of the array that we shifted out
+ // of. This is fine because the caller is required to store over that area, and
+ // in contiguous mode storing into a hole is guaranteed to behave exactly the same
+ // as storing over an existing element.
+
+ return true;
+ }
+
case ArrayWithArrayStorage:
case ArrayWithSlowPutArrayStorage:
return unshiftCountWithArrayStorage(exec, startIndex, count, arrayStorage());
@@ -778,6 +940,20 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
}
}
+static int compareNumbersForQSortWithInt32(const void* a, const void* b)
+{
+ int32_t ia = static_cast<const JSValue*>(a)->asInt32();
+ int32_t ib = static_cast<const JSValue*>(b)->asInt32();
+ return ia - ib;
+}
+
+static int compareNumbersForQSortWithDouble(const void* a, const void* b)
+{
+ double da = *static_cast<const double*>(a);
+ double db = *static_cast<const double*>(b);
+ return (da > db) - (da < db);
+}
+
static int compareNumbersForQSort(const void* a, const void* b)
{
double da = static_cast<const JSValue*>(a)->asNumber();
@@ -795,7 +971,7 @@ static int compareByStringPairForQSort(const void* a, const void* b)
template<IndexingType indexingType>
void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
{
- ASSERT(indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage);
+ ASSERT(indexingType == ArrayWithInt32 || indexingType == ArrayWithDouble || indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage);
unsigned lengthNotIncludingUndefined;
unsigned newRelevantLength;
@@ -814,11 +990,19 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy
return;
bool allValuesAreNumbers = true;
- for (size_t i = 0; i < newRelevantLength; ++i) {
- if (!data[i].isNumber()) {
- allValuesAreNumbers = false;
- break;
+ switch (indexingType) {
+ case ArrayWithInt32:
+ case ArrayWithDouble:
+ break;
+
+ default:
+ for (size_t i = 0; i < newRelevantLength; ++i) {
+ if (!data[i].isNumber()) {
+ allValuesAreNumbers = false;
+ break;
+ }
}
+ break;
}
if (!allValuesAreNumbers)
@@ -827,7 +1011,23 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy
// For numeric comparison, which is fast, qsort is faster than mergesort. We
// also don't require mergesort's stability, since there's no user visible
// side-effect from swapping the order of equal primitive values.
- qsort(data, newRelevantLength, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort);
+ int (*compare)(const void*, const void*);
+ switch (indexingType) {
+ case ArrayWithInt32:
+ compare = compareNumbersForQSortWithInt32;
+ break;
+
+ case ArrayWithDouble:
+ compare = compareNumbersForQSortWithDouble;
+ ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(double));
+ break;
+
+ default:
+ compare = compareNumbersForQSort;
+ break;
+ }
+
+ qsort(data, newRelevantLength, sizeof(WriteBarrier<Unknown>), compare);
return;
}
@@ -839,6 +1039,14 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal
case ArrayClass:
return;
+ case ArrayWithInt32:
+ sortNumericVector<ArrayWithInt32>(exec, compareFunction, callType, callData);
+ break;
+
+ case ArrayWithDouble:
+ sortNumericVector<ArrayWithDouble>(exec, compareFunction, callType, callData);
+ break;
+
case ArrayWithContiguous:
sortNumericVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
return;
@@ -854,7 +1062,7 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal
}
template<IndexingType indexingType>
-void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin, unsigned relevantLength)
+void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevantLength)
{
if (!relevantLength)
return;
@@ -875,11 +1083,31 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin,
Heap::heap(this)->pushTempSortVector(&values);
bool isSortingPrimitiveValues = true;
- for (size_t i = 0; i < relevantLength; i++) {
- JSValue value = begin[i].get();
- ASSERT(!value.isUndefined());
- values[i].first = value;
- isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
+ switch (indexingType) {
+ case ArrayWithInt32:
+ for (size_t i = 0; i < relevantLength; i++) {
+ JSValue value = static_cast<WriteBarrier<Unknown>*>(begin)[i].get();
+ ASSERT(value.isInt32());
+ values[i].first = value;
+ }
+ break;
+
+ case ArrayWithDouble:
+ for (size_t i = 0; i < relevantLength; i++) {
+ double value = static_cast<double*>(begin)[i];
+ ASSERT(value == value);
+ values[i].first = JSValue(JSValue::EncodeAsDouble, value);
+ }
+ break;
+
+ default:
+ for (size_t i = 0; i < relevantLength; i++) {
+ JSValue value = static_cast<WriteBarrier<Unknown>*>(begin)[i].get();
+ ASSERT(!value.isUndefined());
+ values[i].first = value;
+ isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
+ }
+ break;
}
// FIXME: The following loop continues to call toString on subsequent values even after
@@ -910,8 +1138,10 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin,
// If the toString function changed the length of the array or vector storage,
// increase the length to handle the orignal number of actual values.
switch (indexingType) {
+ case ArrayWithInt32:
+ case ArrayWithDouble:
case ArrayWithContiguous:
- ensureContiguousLength(globalData, relevantLength);
+ ensureLength(globalData, relevantLength);
break;
case ArrayWithArrayStorage:
@@ -927,8 +1157,12 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin,
CRASH();
}
- for (size_t i = 0; i < relevantLength; i++)
- begin[i].set(globalData, this, values[i].first);
+ for (size_t i = 0; i < relevantLength; i++) {
+ if (indexingType == ArrayWithDouble)
+ static_cast<double*>(begin)[i] = values[i].first.asNumber();
+ else
+ static_cast<WriteBarrier<Unknown>*>(begin)[i].set(globalData, this, values[i].first);
+ }
Heap::heap(this)->popTempSortVector(&values);
}
@@ -939,8 +1173,31 @@ void JSArray::sort(ExecState* exec)
switch (structure()->indexingType()) {
case ArrayClass:
+ case ArrayWithUndecided:
return;
+ case ArrayWithInt32: {
+ unsigned lengthNotIncludingUndefined;
+ unsigned newRelevantLength;
+ compactForSorting<ArrayWithInt32>(
+ lengthNotIncludingUndefined, newRelevantLength);
+
+ sortCompactedVector<ArrayWithInt32>(
+ exec, m_butterfly->contiguousInt32(), lengthNotIncludingUndefined);
+ return;
+ }
+
+ case ArrayWithDouble: {
+ unsigned lengthNotIncludingUndefined;
+ unsigned newRelevantLength;
+ compactForSorting<ArrayWithDouble>(
+ lengthNotIncludingUndefined, newRelevantLength);
+
+ sortCompactedVector<ArrayWithDouble>(
+ exec, m_butterfly->contiguousDouble(), lengthNotIncludingUndefined);
+ return;
+ }
+
case ArrayWithContiguous: {
unsigned lengthNotIncludingUndefined;
unsigned newRelevantLength;
@@ -1087,12 +1344,12 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
unsigned numDefined = 0;
unsigned numUndefined = 0;
-
+
// Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
for (; numDefined < usedVectorLength; ++numDefined) {
if (numDefined > m_butterfly->vectorLength())
break;
- JSValue v = currentIndexingData()[numDefined].get();
+ JSValue v = getHolyIndexQuickly(numDefined);
if (!v || v.isUndefined())
break;
tree.abstractor().m_nodes[numDefined].value = v;
@@ -1101,7 +1358,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
for (unsigned i = numDefined; i < usedVectorLength; ++i) {
if (i > m_butterfly->vectorLength())
break;
- JSValue v = currentIndexingData()[i].get();
+ JSValue v = getHolyIndexQuickly(i);
if (v) {
if (v.isUndefined())
++numUndefined;
@@ -1112,7 +1369,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
}
}
}
-
+
unsigned newUsedVectorLength = numDefined + numUndefined;
// The array size may have changed. Figure out the new bounds.
@@ -1127,16 +1384,31 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
iter.start_iter_least(tree);
JSGlobalData& globalData = exec->globalData();
for (unsigned i = 0; i < elementsToExtractThreshold; ++i) {
- currentIndexingData()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
+ if (structure()->indexingType() == ArrayWithDouble)
+ butterfly()->contiguousDouble()[i] = tree.abstractor().m_nodes[*iter].value.asNumber();
+ else
+ currentIndexingData()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
++iter;
}
// Put undefined values back in.
- for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i)
- currentIndexingData()[i].setUndefined();
+ switch (structure()->indexingType()) {
+ case ArrayWithInt32:
+ case ArrayWithDouble:
+ ASSERT(elementsToExtractThreshold == undefinedElementsThreshold);
+ break;
+
+ default:
+ for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i)
+ currentIndexingData()[i].setUndefined();
+ }
// Ensure that unused values in the vector are zeroed out.
- for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i)
- currentIndexingData()[i].clear();
+ for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) {
+ if (structure()->indexingType() == ArrayWithDouble)
+ butterfly()->contiguousDouble()[i] = QNaN;
+ else
+ currentIndexingData()[i].clear();
+ }
if (hasArrayStorage(structure()->indexingType()))
arrayStorage()->m_numValuesInVector = newUsedVectorLength;
@@ -1148,8 +1420,17 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,
switch (structure()->indexingType()) {
case ArrayClass:
+ case ArrayWithUndecided:
return;
+ case ArrayWithInt32:
+ sortVector<ArrayWithInt32>(exec, compareFunction, callType, callData);
+ return;
+
+ case ArrayWithDouble:
+ sortVector<ArrayWithDouble>(exec, compareFunction, callType, callData);
+ return;
+
case ArrayWithContiguous:
sortVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
return;
@@ -1173,11 +1454,30 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
case ArrayClass:
return;
+ case ArrayWithUndecided: {
+ vector = 0;
+ vectorEnd = 0;
+ break;
+ }
+
+ case ArrayWithInt32:
case ArrayWithContiguous: {
vectorEnd = m_butterfly->publicLength();
vector = m_butterfly->contiguous();
break;
}
+
+ case ArrayWithDouble: {
+ vector = 0;
+ vectorEnd = 0;
+ for (; i < m_butterfly->publicLength(); ++i) {
+ double v = butterfly()->contiguousDouble()[i];
+ if (v != v)
+ break;
+ args.append(JSValue(JSValue::EncodeAsDouble, v));
+ }
+ break;
+ }
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
@@ -1216,12 +1516,31 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le
case ArrayClass:
return;
+ case ArrayWithUndecided: {
+ vector = 0;
+ vectorEnd = 0;
+ break;
+ }
+
+ case ArrayWithInt32:
case ArrayWithContiguous: {
vector = m_butterfly->contiguous();
vectorEnd = m_butterfly->publicLength();
break;
}
+ case ArrayWithDouble: {
+ vector = 0;
+ vectorEnd = 0;
+ for (; i < m_butterfly->publicLength(); ++i) {
+ double v = m_butterfly->contiguousDouble()[i];
+ if (v != v)
+ break;
+ callFrame->setArgument(i, JSValue(JSValue::EncodeAsDouble, v));
+ }
+ break;
+ }
+
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
vector = storage->m_vector;
@@ -1259,12 +1578,40 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt
unsigned numUndefined = 0;
for (; numDefined < myRelevantLength; ++numDefined) {
+ if (indexingType == ArrayWithInt32) {
+ JSValue v = m_butterfly->contiguousInt32()[numDefined].get();
+ if (!v)
+ break;
+ ASSERT(v.isInt32());
+ continue;
+ }
+ if (indexingType == ArrayWithDouble) {
+ double v = m_butterfly->contiguousDouble()[numDefined];
+ if (v != v)
+ break;
+ continue;
+ }
JSValue v = indexingData<indexingType>()[numDefined].get();
if (!v || v.isUndefined())
break;
}
for (unsigned i = numDefined; i < myRelevantLength; ++i) {
+ if (indexingType == ArrayWithInt32) {
+ JSValue v = m_butterfly->contiguousInt32()[i].get();
+ if (!v)
+ continue;
+ ASSERT(v.isInt32());
+ m_butterfly->contiguousInt32()[numDefined++].setWithoutWriteBarrier(v);
+ continue;
+ }
+ if (indexingType == ArrayWithDouble) {
+ double v = m_butterfly->contiguousDouble()[i];
+ if (v != v)
+ continue;
+ m_butterfly->contiguousDouble()[numDefined++] = v;
+ continue;
+ }
JSValue v = indexingData<indexingType>()[i].get();
if (v) {
if (v.isUndefined())
@@ -1279,10 +1626,23 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt
if (hasArrayStorage(indexingType))
ASSERT(!arrayStorage()->m_sparseMap);
- for (unsigned i = numDefined; i < newRelevantLength; ++i)
- indexingData<indexingType>()[i].setUndefined();
- for (unsigned i = newRelevantLength; i < myRelevantLength; ++i)
- indexingData<indexingType>()[i].clear();
+ switch (indexingType) {
+ case ArrayWithInt32:
+ case ArrayWithDouble:
+ ASSERT(numDefined == newRelevantLength);
+ break;
+
+ default:
+ for (unsigned i = numDefined; i < newRelevantLength; ++i)
+ indexingData<indexingType>()[i].setUndefined();
+ break;
+ }
+ for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) {
+ if (indexingType == ArrayWithDouble)
+ m_butterfly->contiguousDouble()[i] = QNaN;
+ else
+ indexingData<indexingType>()[i].clear();
+ }
if (hasArrayStorage(indexingType))
arrayStorage()->m_numValuesInVector = newRelevantLength;
diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h
index 1d1e64173..ea1ed9047 100644
--- a/Source/JavaScriptCore/runtime/JSArray.h
+++ b/Source/JavaScriptCore/runtime/JSArray.h
@@ -22,7 +22,7 @@
#define JSArray_h
#include "ArrayConventions.h"
-#include "ButterflyInlineMethods.h"
+#include "ButterflyInlines.h"
#include "JSObject.h"
namespace JSC {
@@ -162,7 +162,7 @@ private:
void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
template<IndexingType indexingType>
- void sortCompactedVector(ExecState*, WriteBarrier<Unknown>* begin, unsigned relevantLength);
+ void sortCompactedVector(ExecState*, void* begin, unsigned relevantLength);
template<IndexingType indexingType>
void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
@@ -174,13 +174,14 @@ private:
void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength);
};
-inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length)
+inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length, unsigned& vectorLength)
{
IndexingHeader header;
- header.setVectorLength(std::max(length, BASE_VECTOR_LEN));
+ vectorLength = std::max(length, BASE_VECTOR_LEN);
+ header.setVectorLength(vectorLength);
header.setPublicLength(length);
Butterfly* result = Butterfly::create(
- globalData, 0, 0, true, header, header.vectorLength() * sizeof(EncodedJSValue));
+ globalData, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue));
return result;
}
@@ -200,13 +201,23 @@ Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData&, unsigned
inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength)
{
Butterfly* butterfly;
- if (LIKELY(structure->indexingType() == ArrayWithContiguous)) {
- butterfly = createContiguousArrayButterfly(globalData, initialLength);
+ if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
+ ASSERT(
+ hasUndecided(structure->indexingType())
+ || hasInt32(structure->indexingType())
+ || hasDouble(structure->indexingType())
+ || hasContiguous(structure->indexingType()));
+ unsigned vectorLength;
+ butterfly = createContiguousArrayButterfly(globalData, initialLength, vectorLength);
ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX);
+ if (hasDouble(structure->indexingType())) {
+ for (unsigned i = 0; i < vectorLength; ++i)
+ butterfly->contiguousDouble()[i] = QNaN;
+ }
} else {
ASSERT(
structure->indexingType() == ArrayWithSlowPutArrayStorage
- || (initialLength && structure->indexingType() == ArrayWithArrayStorage));
+ || structure->indexingType() == ArrayWithArrayStorage);
butterfly = createArrayButterfly(globalData, initialLength);
}
JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly);
@@ -221,8 +232,13 @@ inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Struct
return 0;
Butterfly* butterfly;
- if (LIKELY(structure->indexingType() == ArrayWithContiguous)) {
-
+ if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
+ ASSERT(
+ hasUndecided(structure->indexingType())
+ || hasInt32(structure->indexingType())
+ || hasDouble(structure->indexingType())
+ || hasContiguous(structure->indexingType()));
+
void* temp;
if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp))
return 0;
diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h
index 3b37613d1..df31b8542 100644
--- a/Source/JavaScriptCore/runtime/JSCell.h
+++ b/Source/JavaScriptCore/runtime/JSCell.h
@@ -28,9 +28,9 @@
#include "ConstructData.h"
#include "Heap.h"
#include "JSLock.h"
-#include "JSValueInlineMethods.h"
+#include "JSValueInlines.h"
#include "SlotVisitor.h"
-#include "SlotVisitorInlineMethods.h"
+#include "SlotVisitorInlines.h"
#include "TypedArrayDescriptor.h"
#include "WriteBarrier.h"
#include <wtf/Noncopyable.h>
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index c466a2b04..a7c6c8c18 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -230,9 +230,16 @@ void JSGlobalObject::reset(JSValue prototype)
m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSDestructibleObject>::createStructure(exec->globalData(), this, m_objectPrototype.get()));
m_arrayPrototype.set(exec->globalData(), this, ArrayPrototype::create(exec, this, ArrayPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
- m_arrayStructure.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithContiguous));
- m_arrayStructureWithArrayStorage.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage));
- m_arrayStructureForSlowPut.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage));
+
+ m_originalArrayStructureForIndexingShape[UndecidedShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithUndecided));
+ m_originalArrayStructureForIndexingShape[Int32Shape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithInt32));
+ m_originalArrayStructureForIndexingShape[DoubleShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithDouble));
+ m_originalArrayStructureForIndexingShape[ContiguousShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithContiguous));
+ m_originalArrayStructureForIndexingShape[ArrayStorageShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage));
+ m_originalArrayStructureForIndexingShape[SlowPutArrayStorageShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage));
+ for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+ m_arrayStructureForIndexingShapeDuringAllocation[i] = m_originalArrayStructureForIndexingShape[i];
+
m_regExpMatchesArrayStructure.set(exec->globalData(), this, RegExpMatchesArray::createStructure(exec->globalData(), this, m_arrayPrototype.get()));
m_stringPrototype.set(exec->globalData(), this, StringPrototype::create(exec, this, StringPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
@@ -360,7 +367,9 @@ inline bool hasBrokenIndexing(JSObject* object)
{
// This will change if we have more indexing types.
IndexingType type = object->structure()->indexingType();
- return hasContiguous(type) || hasFastArrayStorage(type);
+ // This could be made obviously more efficient, but isn't made so right now, because
+ // we expect this to be an unlikely slow path anyway.
+ return hasUndecided(type) || hasInt32(type) || hasDouble(type) || hasContiguous(type) || hasFastArrayStorage(type);
}
void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell)
@@ -412,8 +421,8 @@ void JSGlobalObject::haveABadTime(JSGlobalData& globalData)
// Make sure that all JSArray allocations that load the appropriate structure from
// this object now load a structure that uses SlowPut.
- m_arrayStructure.set(globalData, this, m_arrayStructureForSlowPut.get());
- m_arrayStructureWithArrayStorage.set(globalData, this, m_arrayStructureForSlowPut.get());
+ for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+ m_arrayStructureForIndexingShapeDuringAllocation[i].set(globalData, this, originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage));
// Make sure that all objects that have indexed storage switch to the slow kind of
// indexed storage.
@@ -488,9 +497,10 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&thisObject->m_activationStructure);
visitor.append(&thisObject->m_nameScopeStructure);
visitor.append(&thisObject->m_argumentsStructure);
- visitor.append(&thisObject->m_arrayStructure);
- visitor.append(&thisObject->m_arrayStructureWithArrayStorage);
- visitor.append(&thisObject->m_arrayStructureForSlowPut);
+ for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+ visitor.append(&thisObject->m_originalArrayStructureForIndexingShape[i]);
+ for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+ visitor.append(&thisObject->m_arrayStructureForIndexingShapeDuringAllocation[i]);
visitor.append(&thisObject->m_booleanObjectStructure);
visitor.append(&thisObject->m_callbackConstructorStructure);
visitor.append(&thisObject->m_callbackFunctionStructure);
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index 3212363ab..121b71b72 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -22,6 +22,7 @@
#ifndef JSGlobalObject_h
#define JSGlobalObject_h
+#include "ArrayAllocationProfile.h"
#include "JSArray.h"
#include "JSGlobalData.h"
#include "JSSegmentedVariableObject.h"
@@ -130,9 +131,12 @@ namespace JSC {
WriteBarrier<Structure> m_activationStructure;
WriteBarrier<Structure> m_nameScopeStructure;
WriteBarrier<Structure> m_argumentsStructure;
- WriteBarrier<Structure> m_arrayStructure; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time.
- WriteBarrier<Structure> m_arrayStructureWithArrayStorage; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time.
- WriteBarrier<Structure> m_arrayStructureForSlowPut;
+
+ // Lists the actual structures used for having these particular indexing shapes.
+ WriteBarrier<Structure> m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes];
+ // Lists the structures we should use during allocation for these particular indexing shapes.
+ WriteBarrier<Structure> m_arrayStructureForIndexingShapeDuringAllocation[NumberOfIndexingShapes];
+
WriteBarrier<Structure> m_booleanObjectStructure;
WriteBarrier<Structure> m_callbackConstructorStructure;
WriteBarrier<Structure> m_callbackFunctionStructure;
@@ -275,14 +279,26 @@ namespace JSC {
Structure* activationStructure() const { return m_activationStructure.get(); }
Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); }
Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
- Structure* arrayStructure() const { return m_arrayStructure.get(); }
- Structure* arrayStructureWithArrayStorage() const { return m_arrayStructureWithArrayStorage.get(); }
- void* addressOfArrayStructure() { return &m_arrayStructure; }
- void* addressOfArrayStructureWithArrayStorage() { return &m_arrayStructureWithArrayStorage; }
+ Structure* originalArrayStructureForIndexingType(IndexingType indexingType) const
+ {
+ ASSERT(indexingType & IsArray);
+ return m_originalArrayStructureForIndexingShape[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get();
+ }
+ Structure* arrayStructureForIndexingTypeDuringAllocation(IndexingType indexingType) const
+ {
+ ASSERT(indexingType & IsArray);
+ return m_arrayStructureForIndexingShapeDuringAllocation[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get();
+ }
+ Structure* arrayStructureForProfileDuringAllocation(ArrayAllocationProfile* profile) const
+ {
+ return arrayStructureForIndexingTypeDuringAllocation(ArrayAllocationProfile::selectIndexingTypeFor(profile));
+ }
+
bool isOriginalArrayStructure(Structure* structure)
{
- return structure == m_arrayStructure.get() || structure == m_arrayStructureWithArrayStorage.get();
+ return originalArrayStructureForIndexingType(structure->indexingType() | IsArray) == structure;
}
+
Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
@@ -497,34 +513,34 @@ namespace JSC {
return constructEmptyObject(exec, exec->lexicalGlobalObject());
}
- inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength = 0)
+ inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0)
{
- return JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureWithArrayStorage() : globalObject->arrayStructure(), initialLength);
+ return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength));
}
- inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength = 0)
+ inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0)
{
- return constructEmptyArray(exec, exec->lexicalGlobalObject(), initialLength);
+ return constructEmptyArray(exec, profile, exec->lexicalGlobalObject(), initialLength);
}
- inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const ArgList& values)
+ inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList& values)
{
- return constructArray(exec, globalObject->arrayStructure(), values);
+ return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values));
}
- inline JSArray* constructArray(ExecState* exec, const ArgList& values)
+ inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList& values)
{
- return constructArray(exec, exec->lexicalGlobalObject(), values);
+ return constructArray(exec, profile, exec->lexicalGlobalObject(), values);
}
- inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
+ inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
{
- return constructArray(exec, globalObject->arrayStructure(), values, length);
+ return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values, length));
}
- inline JSArray* constructArray(ExecState* exec, const JSValue* values, unsigned length)
+ inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length)
{
- return constructArray(exec, exec->lexicalGlobalObject(), values, length);
+ return constructArray(exec, profile, exec->lexicalGlobalObject(), values, length);
}
class DynamicGlobalObjectScope {
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 6a3fb84e4..a67896b1a 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -24,14 +24,14 @@
#include "config.h"
#include "JSObject.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
+#include "CopiedSpaceInlines.h"
#include "CopyVisitor.h"
-#include "CopyVisitorInlineMethods.h"
+#include "CopyVisitorInlines.h"
#include "DatePrototype.h"
#include "ErrorConstructor.h"
#include "GetterSetter.h"
-#include "IndexingHeaderInlineMethods.h"
+#include "IndexingHeaderInlines.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "Lookup.h"
@@ -42,7 +42,7 @@
#include "PropertyDescriptor.h"
#include "PropertyNameArray.h"
#include "Reject.h"
-#include "SlotVisitorInlineMethods.h"
+#include "SlotVisitorInlines.h"
#include <math.h>
#include <wtf/Assertions.h>
@@ -129,7 +129,16 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt
size_t count;
switch (structure->indexingType()) {
- case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ case ALL_UNDECIDED_INDEXING_TYPES: {
+ currentTarget = 0;
+ currentSource = 0;
+ count = 0;
+ break;
+ }
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES: {
currentTarget = newButterfly->contiguous();
currentSource = butterfly->contiguous();
ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength());
@@ -152,8 +161,7 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt
break;
}
- while (count--)
- (currentTarget++)->setWithoutWriteBarrier((currentSource++)->get());
+ memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue));
}
m_butterfly = newButterfly;
@@ -272,8 +280,10 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
switch (thisObject->structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
break;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = thisObject->m_butterfly;
if (i >= butterfly->vectorLength())
@@ -288,6 +298,20 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
return false;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return false;
+
+ double value = butterfly->contiguousDouble()[i];
+ if (value == value) {
+ slot.setValue(JSValue(JSValue::EncodeAsDouble, value));
+ return true;
+ }
+
+ return false;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
if (i >= storage->length())
@@ -405,6 +429,22 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
case ALL_BLANK_INDEXING_TYPES:
break;
+ case ALL_UNDECIDED_INDEXING_TYPES: {
+ thisObject->convertUndecidedForValue(exec->globalData(), value);
+ // Reloop.
+ putByIndex(cell, exec, propertyName, value, shouldThrow);
+ return;
+ }
+
+ case ALL_INT32_INDEXING_TYPES: {
+ if (!value.isInt32()) {
+ thisObject->convertInt32ForValue(exec->globalData(), value);
+ putByIndex(cell, exec, propertyName, value, shouldThrow);
+ return;
+ }
+ // Fall through.
+ }
+
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = thisObject->m_butterfly;
if (propertyName >= butterfly->vectorLength())
@@ -415,6 +455,29 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
return;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ if (!value.isNumber()) {
+ thisObject->convertDoubleToContiguous(exec->globalData());
+ // Reloop.
+ putByIndex(cell, exec, propertyName, value, shouldThrow);
+ return;
+ }
+ double valueAsDouble = value.asNumber();
+ if (valueAsDouble != valueAsDouble) {
+ thisObject->convertDoubleToContiguous(exec->globalData());
+ // Reloop.
+ putByIndex(cell, exec, propertyName, value, shouldThrow);
+ return;
+ }
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (propertyName >= butterfly->vectorLength())
+ break;
+ butterfly->contiguousDouble()[propertyName] = valueAsDouble;
+ if (propertyName >= butterfly->publicLength())
+ butterfly->setPublicLength(propertyName + 1);
+ return;
+ }
+
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
@@ -507,10 +570,13 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
void JSObject::enterDictionaryIndexingMode(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
// NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize
// this case if we ever cared.
- enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData));
+ enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, ensureArrayStorageSlow(globalData));
break;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
@@ -534,7 +600,7 @@ void JSObject::notifyPresenceOfIndexedAccessors(JSGlobalData& globalData)
globalObject()->haveABadTime(globalData);
}
-WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length)
+Butterfly* JSObject::createInitialIndexedStorage(JSGlobalData& globalData, unsigned length, size_t elementSize)
{
ASSERT(length < MAX_ARRAY_INDEX);
IndexingType oldType = structure()->indexingType();
@@ -544,9 +610,41 @@ WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalDat
unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
Butterfly* newButterfly = m_butterfly->growArrayRight(
globalData, structure(), structure()->outOfLineCapacity(), false, 0,
- sizeof(EncodedJSValue) * vectorLength);
+ elementSize * vectorLength);
newButterfly->setPublicLength(length);
newButterfly->setVectorLength(vectorLength);
+ return newButterfly;
+}
+
+Butterfly* JSObject::createInitialUndecided(JSGlobalData& globalData, unsigned length)
+{
+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue));
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateUndecided);
+ setButterfly(globalData, newButterfly, newStructure);
+ return newButterfly;
+}
+
+WriteBarrier<Unknown>* JSObject::createInitialInt32(JSGlobalData& globalData, unsigned length)
+{
+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue));
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateInt32);
+ setButterfly(globalData, newButterfly, newStructure);
+ return newButterfly->contiguousInt32();
+}
+
+double* JSObject::createInitialDouble(JSGlobalData& globalData, unsigned length)
+{
+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(double));
+ for (unsigned i = newButterfly->vectorLength(); i--;)
+ newButterfly->contiguousDouble()[i] = QNaN;
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateDouble);
+ setButterfly(globalData, newButterfly, newStructure);
+ return newButterfly->contiguousDouble();
+}
+
+WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length)
+{
+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue));
Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous);
setButterfly(globalData, newButterfly, newStructure);
return newButterfly->contiguous();
@@ -577,10 +675,33 @@ ArrayStorage* JSObject::createInitialArrayStorage(JSGlobalData& globalData)
return createArrayStorage(globalData, 0, BASE_VECTOR_LEN);
}
-ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+WriteBarrier<Unknown>* JSObject::convertUndecidedToInt32(JSGlobalData& globalData)
{
- ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT(hasUndecided(structure()->indexingType()));
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateInt32));
+ return m_butterfly->contiguousInt32();
+}
+
+double* JSObject::convertUndecidedToDouble(JSGlobalData& globalData)
+{
+ ASSERT(hasUndecided(structure()->indexingType()));
+
+ for (unsigned i = m_butterfly->vectorLength(); i--;)
+ m_butterfly->contiguousDouble()[i] = QNaN;
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateDouble));
+ return m_butterfly->contiguousDouble();
+}
+
+WriteBarrier<Unknown>* JSObject::convertUndecidedToContiguous(JSGlobalData& globalData)
+{
+ ASSERT(hasUndecided(structure()->indexingType()));
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous));
+ return m_butterfly->contiguous();
+}
+
+ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(JSGlobalData& globalData, unsigned neededLength)
+{
unsigned publicLength = m_butterfly->publicLength();
unsigned propertyCapacity = structure()->outOfLineCapacity();
unsigned propertySize = structure()->outOfLineSize();
@@ -599,7 +720,66 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData
newStorage->m_sparseMap.clear();
newStorage->m_indexBias = 0;
newStorage->m_numValuesInVector = 0;
- for (unsigned i = publicLength; i--;) {
+
+ return newStorage;
+}
+
+ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+{
+ ASSERT(hasUndecided(structure()->indexingType()));
+
+ ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength);
+ // No need to copy elements.
+
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition);
+ setButterfly(globalData, storage->butterfly(), newStructure);
+ return storage;
+}
+
+ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition)
+{
+ return convertUndecidedToArrayStorage(globalData, transition, m_butterfly->vectorLength());
+}
+
+ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData)
+{
+ return convertUndecidedToArrayStorage(globalData, structure()->suggestedArrayStorageTransition());
+}
+
+double* JSObject::convertInt32ToDouble(JSGlobalData& globalData)
+{
+ ASSERT(hasInt32(structure()->indexingType()));
+
+ for (unsigned i = m_butterfly->vectorLength(); i--;) {
+ WriteBarrier<Unknown>* current = &m_butterfly->contiguousInt32()[i];
+ double* currentAsDouble = bitwise_cast<double*>(current);
+ JSValue v = current->get();
+ if (!v) {
+ *currentAsDouble = QNaN;
+ continue;
+ }
+ ASSERT(v.isInt32());
+ *currentAsDouble = v.asInt32();
+ }
+
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateDouble));
+ return m_butterfly->contiguousDouble();
+}
+
+WriteBarrier<Unknown>* JSObject::convertInt32ToContiguous(JSGlobalData& globalData)
+{
+ ASSERT(hasInt32(structure()->indexingType()));
+
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous));
+ return m_butterfly->contiguous();
+}
+
+ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+{
+ ASSERT(hasInt32(structure()->indexingType()));
+
+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength);
+ for (unsigned i = m_butterfly->publicLength(); i--;) {
JSValue v = m_butterfly->contiguous()[i].get();
if (!v)
continue;
@@ -608,7 +788,82 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData
}
Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition);
- setButterfly(globalData, newButterfly, newStructure);
+ setButterfly(globalData, newStorage->butterfly(), newStructure);
+ return newStorage;
+}
+
+ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition)
+{
+ return convertInt32ToArrayStorage(globalData, transition, m_butterfly->vectorLength());
+}
+
+ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData)
+{
+ return convertInt32ToArrayStorage(globalData, structure()->suggestedArrayStorageTransition());
+}
+
+WriteBarrier<Unknown>* JSObject::convertDoubleToContiguous(JSGlobalData& globalData)
+{
+ ASSERT(hasDouble(structure()->indexingType()));
+
+ for (unsigned i = m_butterfly->vectorLength(); i--;) {
+ double* current = &m_butterfly->contiguousDouble()[i];
+ WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current);
+ double value = *current;
+ if (value != value) {
+ currentAsValue->clear();
+ continue;
+ }
+ currentAsValue->setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
+ }
+
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous));
+ return m_butterfly->contiguous();
+}
+
+ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+{
+ ASSERT(hasDouble(structure()->indexingType()));
+
+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength);
+ for (unsigned i = m_butterfly->publicLength(); i--;) {
+ double value = m_butterfly->contiguousDouble()[i];
+ if (value != value)
+ continue;
+ newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
+ newStorage->m_numValuesInVector++;
+ }
+
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition);
+ setButterfly(globalData, newStorage->butterfly(), newStructure);
+ return newStorage;
+}
+
+ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition)
+{
+ return convertDoubleToArrayStorage(globalData, transition, m_butterfly->vectorLength());
+}
+
+ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData)
+{
+ return convertDoubleToArrayStorage(globalData, structure()->suggestedArrayStorageTransition());
+}
+
+ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+{
+ ASSERT(hasContiguous(structure()->indexingType()));
+
+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength);
+ for (unsigned i = m_butterfly->publicLength(); i--;) {
+ JSValue v = m_butterfly->contiguous()[i].get();
+ if (!v)
+ continue;
+ newStorage->m_vector[i].setWithoutWriteBarrier(v);
+ newStorage->m_numValuesInVector++;
+ }
+
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition);
+ setButterfly(globalData, newStorage->butterfly(), newStructure);
return newStorage;
}
@@ -622,48 +877,154 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData
return convertContiguousToArrayStorage(globalData, structure()->suggestedArrayStorageTransition());
}
-WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData)
+void JSObject::convertUndecidedForValue(JSGlobalData& globalData, JSValue value)
+{
+ if (value.isInt32()) {
+ convertUndecidedToInt32(globalData);
+ return;
+ }
+
+ if (value.isDouble()) {
+ convertUndecidedToDouble(globalData);
+ return;
+ }
+
+ convertUndecidedToContiguous(globalData);
+}
+
+void JSObject::convertInt32ForValue(JSGlobalData& globalData, JSValue value)
+{
+ ASSERT(!value.isInt32());
+
+ if (value.isDouble()) {
+ convertInt32ToDouble(globalData);
+ return;
+ }
+
+ convertInt32ToContiguous(globalData);
+}
+
+void JSObject::setIndexQuicklyToUndecided(JSGlobalData& globalData, unsigned index, JSValue value)
+{
+ ASSERT(index < m_butterfly->publicLength());
+ ASSERT(index < m_butterfly->vectorLength());
+ convertUndecidedForValue(globalData, value);
+ setIndexQuickly(globalData, index, value);
+}
+
+void JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(JSGlobalData& globalData, unsigned index, JSValue value)
+{
+ ASSERT(!value.isInt32());
+ convertInt32ForValue(globalData, value);
+ setIndexQuickly(globalData, index, value);
+}
+
+void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(JSGlobalData& globalData, unsigned index, JSValue value)
+{
+ ASSERT(!value.isNumber() || value.asNumber() != value.asNumber());
+ convertDoubleToContiguous(globalData);
+ setIndexQuickly(globalData, index, value);
+}
+
+WriteBarrier<Unknown>* JSObject::ensureInt32Slow(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
return 0;
- return createInitialContiguous(globalData, 0);
+ return createInitialInt32(globalData, 0);
+
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return convertUndecidedToInt32(globalData);
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return 0;
default:
- ASSERT_NOT_REACHED();
+ CRASH();
return 0;
}
}
-ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData)
+double* JSObject::ensureDoubleSlow(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ return 0;
+ return createInitialDouble(globalData, 0);
+
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return convertUndecidedToDouble(globalData);
+
+ case ALL_INT32_INDEXING_TYPES:
+ return convertInt32ToDouble(globalData);
+
case ALL_CONTIGUOUS_INDEXING_TYPES:
- ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
- return convertContiguousToArrayStorage(globalData);
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return 0;
+ default:
+ CRASH();
+ return 0;
+ }
+}
+
+WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData)
+{
+ switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse()))
- return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData);
- return createInitialArrayStorage(globalData);
+ if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ return 0;
+ return createInitialContiguous(globalData, 0);
+
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return convertUndecidedToContiguous(globalData);
+
+ case ALL_INT32_INDEXING_TYPES:
+ return convertInt32ToContiguous(globalData);
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ return convertDoubleToContiguous(globalData);
+
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return 0;
default:
- ASSERT_NOT_REACHED();
+ CRASH();
return 0;
}
}
-Butterfly* JSObject::ensureIndexedStorageSlow(JSGlobalData& globalData)
+ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(structure()->needsSlowPutIndexing()))
- return createInitialArrayStorage(globalData)->butterfly();
if (UNLIKELY(indexingShouldBeSparse()))
- return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)->butterfly();
- return Butterfly::fromContiguous(createInitialContiguous(globalData, 0));
+ return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData);
+ return createInitialArrayStorage(globalData);
+
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure()->needsSlowPutIndexing());
+ return convertUndecidedToArrayStorage(globalData);
+
+ case ALL_INT32_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure()->needsSlowPutIndexing());
+ return convertInt32ToArrayStorage(globalData);
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure()->needsSlowPutIndexing());
+ return convertDoubleToArrayStorage(globalData);
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure()->needsSlowPutIndexing());
+ return convertContiguousToArrayStorage(globalData);
default:
ASSERT_NOT_REACHED();
@@ -674,13 +1035,6 @@ Butterfly* JSObject::ensureIndexedStorageSlow(JSGlobalData& globalData)
ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- // FIXME: This could be made way more efficient, if we cared.
- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData));
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
-
case ALL_BLANK_INDEXING_TYPES: {
createArrayStorage(globalData, 0, 0);
SparseArrayValueMap* map = allocateSparseIndexMap(globalData);
@@ -688,8 +1042,23 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J
return arrayStorage();
}
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertUndecidedToArrayStorage(globalData));
+
+ case ALL_INT32_INDEXING_TYPES:
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertInt32ToArrayStorage(globalData));
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertDoubleToArrayStorage(globalData));
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData));
+
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
+
default:
- ASSERT_NOT_REACHED();
+ CRASH();
return 0;
}
}
@@ -697,10 +1066,21 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J
void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
- case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ convertUndecidedToArrayStorage(globalData, AllocateSlowPutArrayStorage);
+ break;
+
+ case ALL_INT32_INDEXING_TYPES:
+ convertInt32ToArrayStorage(globalData, AllocateSlowPutArrayStorage);
+ break;
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ convertDoubleToArrayStorage(globalData, AllocateSlowPutArrayStorage);
+ break;
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
convertContiguousToArrayStorage(globalData, AllocateSlowPutArrayStorage);
break;
- }
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
@@ -710,7 +1090,7 @@ void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData)
}
default:
- ASSERT_NOT_REACHED();
+ CRASH();
break;
}
}
@@ -877,8 +1257,10 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
switch (thisObject->structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return true;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = thisObject->m_butterfly;
if (i >= butterfly->vectorLength())
@@ -887,6 +1269,14 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
return true;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return true;
+ butterfly->contiguousDouble()[i] = QNaN;
+ return true;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
@@ -1058,8 +1448,10 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa
// which almost certainly means a different structure for PropertyNameArray.
switch (object->structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
break;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = object->m_butterfly;
unsigned usedLength = butterfly->publicLength();
@@ -1071,6 +1463,18 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa
break;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = object->m_butterfly;
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ double value = butterfly->contiguousDouble()[i];
+ if (value != value)
+ continue;
+ propertyNames.add(Identifier::from(exec, i));
+ }
+ break;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = object->m_butterfly->arrayStorage();
@@ -1460,9 +1864,10 @@ bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, J
return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow);
}
-void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState* exec, unsigned i, JSValue value)
+template<IndexingType indexingShape>
+void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, unsigned i, JSValue value)
{
- ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT((structure()->indexingType() & IndexingShapeMask) == indexingShape);
ASSERT(!indexingShouldBeSparse());
// For us to get here, the index is either greater than the public length, or greater than
@@ -1473,9 +1878,9 @@ void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState
if (i >= MAX_ARRAY_INDEX - 1
|| (i >= MIN_SPARSE_ARRAY_INDEX
- && !isDenseEnoughForVector(i, countElementsInContiguous(m_butterfly)))) {
+ && !isDenseEnoughForVector(i, countElements<indexingShape>(m_butterfly)))) {
ASSERT(i <= MAX_ARRAY_INDEX);
- convertContiguousToArrayStorage(globalData, AllocateArrayStorage);
+ ensureArrayStorageSlow(globalData);
SparseArrayValueMap* map = allocateSparseIndexMap(globalData);
map->putEntry(exec, this, i, value, false);
ASSERT(i >= arrayStorage()->length());
@@ -1483,10 +1888,30 @@ void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState
return;
}
- ensureContiguousLength(globalData, i + 1);
+ ensureLength(globalData, i + 1);
ASSERT(i < m_butterfly->vectorLength());
- m_butterfly->contiguous()[i].set(globalData, this, value);
+ switch (indexingShape) {
+ case Int32Shape:
+ ASSERT(value.isInt32());
+ m_butterfly->contiguousInt32()[i].setWithoutWriteBarrier(value);
+ break;
+
+ case DoubleShape: {
+ ASSERT(value.isNumber());
+ double valueAsDouble = value.asNumber();
+ ASSERT(valueAsDouble == valueAsDouble);
+ m_butterfly->contiguousDouble()[i] = valueAsDouble;
+ break;
+ }
+
+ case ContiguousShape:
+ m_butterfly->contiguous()[i].set(globalData, this, value);
+ break;
+
+ default:
+ CRASH();
+ }
}
void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage)
@@ -1592,8 +2017,23 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue
break;
}
+ case ALL_UNDECIDED_INDEXING_TYPES: {
+ CRASH();
+ break;
+ }
+
+ case ALL_INT32_INDEXING_TYPES: {
+ putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value);
+ break;
+ }
+
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value);
+ break;
+ }
+
case ALL_CONTIGUOUS_INDEXING_TYPES: {
- putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value);
+ putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value);
break;
}
@@ -1724,12 +2164,49 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
return true;
}
+ case ALL_UNDECIDED_INDEXING_TYPES: {
+ convertUndecidedForValue(exec->globalData(), value);
+ // Reloop.
+ return putDirectIndex(exec, i, value, attributes, mode);
+ }
+
+ case ALL_INT32_INDEXING_TYPES: {
+ if (attributes & (ReadOnly | Accessor)) {
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, attributes, mode, convertInt32ToArrayStorage(globalData));
+ }
+ if (!value.isInt32()) {
+ convertInt32ForValue(globalData, value);
+ return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
+ }
+ putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value);
+ return true;
+ }
+
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ if (attributes & (ReadOnly | Accessor)) {
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, attributes, mode, convertDoubleToArrayStorage(globalData));
+ }
+ if (!value.isNumber()) {
+ convertDoubleToContiguous(globalData);
+ return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
+ }
+ double valueAsDouble = value.asNumber();
+ if (valueAsDouble != valueAsDouble) {
+ convertDoubleToContiguous(globalData);
+ return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
+ }
+ putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value);
+ return true;
+ }
+
case ALL_CONTIGUOUS_INDEXING_TYPES: {
if (attributes & (ReadOnly | Accessor)) {
return putDirectIndexBeyondVectorLengthWithArrayStorage(
exec, i, value, attributes, mode, convertContiguousToArrayStorage(globalData));
}
- putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value);
+ putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value);
return true;
}
@@ -1769,33 +2246,65 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength)
unsigned vectorLength;
unsigned length;
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- vectorLength = 0;
- length = 0;
- break;
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ if (hasIndexedProperties(structure()->indexingType())) {
vectorLength = m_butterfly->vectorLength();
length = m_butterfly->publicLength();
- break;
- default:
- CRASH();
- return 0;
+ } else {
+ vectorLength = 0;
+ length = 0;
}
+
return getNewVectorLength(vectorLength, length, desiredLength);
}
-unsigned JSObject::countElementsInContiguous(Butterfly* butterfly)
+template<IndexingType indexingShape>
+unsigned JSObject::countElements(Butterfly* butterfly)
{
unsigned numValues = 0;
for (unsigned i = butterfly->publicLength(); i--;) {
- if (butterfly->contiguous()[i])
- numValues++;
+ switch (indexingShape) {
+ case Int32Shape:
+ case ContiguousShape:
+ if (butterfly->contiguous()[i])
+ numValues++;
+ break;
+
+ case DoubleShape: {
+ double value = butterfly->contiguousDouble()[i];
+ if (value == value)
+ numValues++;
+ break;
+ }
+
+ default:
+ CRASH();
+ }
}
return numValues;
}
+unsigned JSObject::countElements()
+{
+ switch (structure()->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return 0;
+
+ case ALL_INT32_INDEXING_TYPES:
+ return countElements<Int32Shape>(m_butterfly);
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ return countElements<DoubleShape>(m_butterfly);
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return countElements<ContiguousShape>(m_butterfly);
+
+ default:
+ CRASH();
+ return 0;
+ }
+}
+
bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength)
{
// This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map
@@ -1839,19 +2348,24 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength
return true;
}
-void JSObject::ensureContiguousLengthSlow(JSGlobalData& globalData, unsigned length)
+void JSObject::ensureLengthSlow(JSGlobalData& globalData, unsigned length)
{
ASSERT(length < MAX_ARRAY_INDEX);
- ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType()));
ASSERT(length > m_butterfly->vectorLength());
unsigned newVectorLength = std::min(
length << 1,
MAX_STORAGE_VECTOR_LENGTH);
+ unsigned oldVectorLength = m_butterfly->vectorLength();
m_butterfly = m_butterfly->growArrayRight(
globalData, structure(), structure()->outOfLineCapacity(), true,
- m_butterfly->vectorLength() * sizeof(EncodedJSValue),
+ oldVectorLength * sizeof(EncodedJSValue),
newVectorLength * sizeof(EncodedJSValue));
+ if (hasDouble(structure()->indexingType())) {
+ for (unsigned i = oldVectorLength; i < newVectorLength; ++i)
+ m_butterfly->contiguousDouble()[i] = QNaN;
+ }
m_butterfly->setVectorLength(newVectorLength);
}
@@ -1881,8 +2395,10 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope
switch (object->structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return false;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = object->m_butterfly;
if (i >= butterfly->vectorLength())
@@ -1894,6 +2410,17 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope
return true;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = object->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return false;
+ double value = butterfly->contiguousDouble()[i];
+ if (value != value)
+ return false;
+ descriptor.setDescriptor(JSValue(JSValue::EncodeAsDouble, value), 0);
+ return true;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = object->m_butterfly->arrayStorage();
if (i >= storage->length())
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 82455390f..f9ae73ed4 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -151,30 +151,16 @@ public:
unsigned getArrayLength() const
{
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
+ if (!hasIndexedProperties(structure()->indexingType()))
return 0;
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->publicLength();
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
+ return m_butterfly->publicLength();
}
unsigned getVectorLength()
{
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
+ if (!hasIndexedProperties(structure()->indexingType()))
return 0;
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->vectorLength();
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
+ return m_butterfly->vectorLength();
}
JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
@@ -214,9 +200,19 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return false;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return i < m_butterfly->vectorLength() && m_butterfly->contiguous()[i];
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ if (i >= m_butterfly->vectorLength())
+ return false;
+ double value = m_butterfly->contiguousDouble()[i];
+ if (value != value)
+ return false;
+ return true;
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i];
default:
@@ -228,8 +224,11 @@ public:
JSValue getIndexQuickly(unsigned i)
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->contiguous()[i].get();
+ case ALL_DOUBLE_INDEXING_TYPES:
+ return JSValue(JSValue::EncodeAsDouble, m_butterfly->contiguousDouble()[i]);
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return m_butterfly->arrayStorage()->m_vector[i].get();
default:
@@ -243,10 +242,19 @@ public:
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
break;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
if (i < m_butterfly->publicLength())
return m_butterfly->contiguous()[i].get();
break;
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ if (i >= m_butterfly->publicLength())
+ break;
+ double result = m_butterfly->contiguousDouble()[i];
+ if (result != result)
+ break;
+ return JSValue(JSValue::EncodeAsDouble, result);
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
if (i < m_butterfly->arrayStorage()->vectorLength())
return m_butterfly->arrayStorage()->m_vector[i].get();
@@ -279,7 +287,10 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return false;
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage:
@@ -298,7 +309,10 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return false;
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return i < m_butterfly->vectorLength();
@@ -311,6 +325,14 @@ public:
void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v)
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isInt32()) {
+ convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ // Fall through to contiguous case.
+ }
case ALL_CONTIGUOUS_INDEXING_TYPES: {
ASSERT(i < m_butterfly->vectorLength());
m_butterfly->contiguous()[i].set(globalData, this, v);
@@ -318,6 +340,22 @@ public:
m_butterfly->setPublicLength(i + 1);
break;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isNumber()) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ double value = v.asNumber();
+ if (value != value) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ m_butterfly->contiguousDouble()[i] = value;
+ if (i >= m_butterfly->publicLength())
+ m_butterfly->setPublicLength(i + 1);
+ break;
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
WriteBarrier<Unknown>& x = storage->m_vector[i];
@@ -338,12 +376,40 @@ public:
void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v)
{
switch (structure()->indexingType()) {
+ case ALL_UNDECIDED_INDEXING_TYPES: {
+ setIndexQuicklyToUndecided(globalData, i, v);
+ break;
+ }
+ case ALL_INT32_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->publicLength());
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isInt32()) {
+ convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v);
+ break;
+ }
+ // Fall through.
+ }
case ALL_CONTIGUOUS_INDEXING_TYPES: {
ASSERT(i < m_butterfly->publicLength());
ASSERT(i < m_butterfly->vectorLength());
m_butterfly->contiguous()[i].set(globalData, this, v);
break;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->publicLength());
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isNumber()) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ double value = v.asNumber();
+ if (value != value) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ m_butterfly->contiguousDouble()[i] = value;
+ break;
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
ASSERT(i < storage->length());
@@ -360,6 +426,9 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return false;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
@@ -374,6 +443,9 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return false;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
@@ -571,6 +643,30 @@ public:
// foo->attemptToInterceptPutByIndexOnHole(...);
bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow);
+ // Returns 0 if int32 storage cannot be created - either because
+ // indexing should be sparse, we're having a bad time, or because
+ // we already have a more general form of storage (double,
+ // contiguous, array storage).
+ WriteBarrier<Unknown>* ensureInt32(JSGlobalData& globalData)
+ {
+ if (LIKELY(hasInt32(structure()->indexingType())))
+ return m_butterfly->contiguousInt32();
+
+ return ensureInt32Slow(globalData);
+ }
+
+ // Returns 0 if double storage cannot be created - either because
+ // indexing should be sparse, we're having a bad time, or because
+ // we already have a more general form of storage (contiguous,
+ // or array storage).
+ double* ensureDouble(JSGlobalData& globalData)
+ {
+ if (LIKELY(hasDouble(structure()->indexingType())))
+ return m_butterfly->contiguousDouble();
+
+ return ensureDoubleSlow(globalData);
+ }
+
// Returns 0 if contiguous storage cannot be created - either because
// indexing should be sparse or because we're having a bad time.
WriteBarrier<Unknown>* ensureContiguous(JSGlobalData& globalData)
@@ -593,14 +689,6 @@ public:
return ensureArrayStorageSlow(globalData);
}
- Butterfly* ensureIndexedStorage(JSGlobalData& globalData)
- {
- if (LIKELY(hasIndexedProperties(structure()->indexingType())))
- return m_butterfly;
-
- return ensureIndexedStorageSlow(globalData);
- }
-
static size_t offsetOfInlineStorage();
static ptrdiff_t butterflyOffset()
@@ -661,19 +749,47 @@ protected:
return 0;
}
}
-
+
+ Butterfly* createInitialUndecided(JSGlobalData&, unsigned length);
+ WriteBarrier<Unknown>* createInitialInt32(JSGlobalData&, unsigned length);
+ double* createInitialDouble(JSGlobalData&, unsigned length);
+ WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length);
+
+ void convertUndecidedForValue(JSGlobalData&, JSValue);
+ void convertInt32ForValue(JSGlobalData&, JSValue);
+
ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength);
ArrayStorage* createInitialArrayStorage(JSGlobalData&);
- WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length);
+
+ WriteBarrier<Unknown>* convertUndecidedToInt32(JSGlobalData&);
+ double* convertUndecidedToDouble(JSGlobalData&);
+ WriteBarrier<Unknown>* convertUndecidedToContiguous(JSGlobalData&);
+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition);
+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&);
+
+ double* convertInt32ToDouble(JSGlobalData&);
+ WriteBarrier<Unknown>* convertInt32ToContiguous(JSGlobalData&);
+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition);
+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&);
+
+ WriteBarrier<Unknown>* convertDoubleToContiguous(JSGlobalData&);
+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition);
+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&);
+
ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition);
ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&);
+
ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&);
bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException);
- void putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState*, unsigned propertyName, JSValue);
+ template<IndexingType indexingShape>
+ void putByIndexBeyondVectorLengthWithoutAttributes(ExecState*, unsigned propertyName, JSValue);
void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*);
bool increaseVectorLength(JSGlobalData&, unsigned newLength);
@@ -687,24 +803,33 @@ protected:
// Call this if you want setIndexQuickly to succeed and you're sure that
// the array is contiguous.
- void ensureContiguousLength(JSGlobalData& globalData, unsigned length)
+ void ensureLength(JSGlobalData& globalData, unsigned length)
{
ASSERT(length < MAX_ARRAY_INDEX);
- ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType()));
if (m_butterfly->vectorLength() < length)
- ensureContiguousLengthSlow(globalData, length);
+ ensureLengthSlow(globalData, length);
if (m_butterfly->publicLength() < length)
m_butterfly->setPublicLength(length);
}
- unsigned countElementsInContiguous(Butterfly*);
+ template<IndexingType indexingShape>
+ unsigned countElements(Butterfly*);
+ // This is relevant to undecided, int32, double, and contiguous.
+ unsigned countElements();
+
+ // This strange method returns a pointer to the start of the indexed data
+ // as if it contained JSValues. But it won't always contain JSValues.
+ // Make sure you cast this to the appropriate type before using.
template<IndexingType indexingType>
WriteBarrier<Unknown>* indexingData()
{
switch (indexingType) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->contiguous();
@@ -720,6 +845,7 @@ protected:
WriteBarrier<Unknown>* currentIndexingData()
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->contiguous();
@@ -732,10 +858,32 @@ protected:
}
}
+ JSValue getHolyIndexQuickly(unsigned i)
+ {
+ switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return m_butterfly->contiguous()[i].get();
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ double value = m_butterfly->contiguousDouble()[i];
+ if (value == value)
+ return JSValue(JSValue::EncodeAsDouble, value);
+ return JSValue();
+ }
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return m_butterfly->arrayStorage()->m_vector[i].get();
+ default:
+ CRASH();
+ return JSValue();
+ }
+ }
+
template<IndexingType indexingType>
unsigned relevantLength()
{
switch (indexingType) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->publicLength();
@@ -753,6 +901,8 @@ protected:
unsigned currentRelevantLength()
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->publicLength();
@@ -778,6 +928,8 @@ private:
void isObject();
void isString();
+ Butterfly* createInitialIndexedStorage(JSGlobalData&, unsigned length, size_t elementSize);
+
ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*);
template<PutMode>
@@ -800,11 +952,18 @@ private:
JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&);
- void ensureContiguousLengthSlow(JSGlobalData&, unsigned length);
+ ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(JSGlobalData&, unsigned neededLength);
+
+ JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(JSGlobalData&, unsigned index, JSValue);
+ JS_EXPORT_PRIVATE void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue);
+ JS_EXPORT_PRIVATE void convertDoubleToContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue);
+
+ void ensureLengthSlow(JSGlobalData&, unsigned length);
+ WriteBarrier<Unknown>* ensureInt32Slow(JSGlobalData&);
+ double* ensureDoubleSlow(JSGlobalData&);
WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&);
ArrayStorage* ensureArrayStorageSlow(JSGlobalData&);
- Butterfly* ensureIndexedStorageSlow(JSGlobalData&);
protected:
Butterfly* m_butterfly;
diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp
index e7f8cad17..8f245f98d 100644
--- a/Source/JavaScriptCore/runtime/JSValue.cpp
+++ b/Source/JavaScriptCore/runtime/JSValue.cpp
@@ -215,8 +215,8 @@ char* JSValue::description() const
#endif
} else if (isCell()) {
snprintf(
- description, size, "Cell: %p (%p: %s, %s)",
- asCell(), asCell()->structure(), asCell()->structure()->classInfo()->className,
+ description, size, "Cell: %p -> %p (%p: %s, %s)",
+ asCell(), isObject() ? asObject(*this)->butterfly() : 0, asCell()->structure(), asCell()->structure()->classInfo()->className,
indexingTypeToString(asCell()->structure()->indexingTypeIncludingHistory()));
} else if (isTrue())
snprintf(description, size, "True");
diff --git a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h b/Source/JavaScriptCore/runtime/JSValueInlines.h
index 224982e9e..c5a42f67f 100644
--- a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h
+++ b/Source/JavaScriptCore/runtime/JSValueInlines.h
@@ -23,8 +23,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef JSValueInlineMethods_h
-#define JSValueInlineMethods_h
+#ifndef JSValueInlines_h
+#define JSValueInlines_h
#include "JSValue.h"
@@ -493,4 +493,5 @@ namespace JSC {
} // namespace JSC
-#endif // JSValueInlineMethods_h
+#endif // JSValueInlines_h
+
diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp
index cd854417b..bf27327bf 100644
--- a/Source/JavaScriptCore/runtime/LiteralParser.cpp
+++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp
@@ -27,8 +27,8 @@
#include "config.h"
#include "LiteralParser.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
+#include "CopiedSpaceInlines.h"
#include "JSArray.h"
#include "JSString.h"
#include "Lexer.h"
@@ -548,7 +548,7 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState)
switch(state) {
startParseArray:
case StartParseArray: {
- JSArray* array = constructEmptyArray(m_exec);
+ JSArray* array = constructEmptyArray(m_exec, 0);
objectStack.append(array);
// fallthrough
}
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
index 7df047d28..7e74a914b 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -21,8 +21,8 @@
#include "config.h"
#include "ObjectConstructor.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
+#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "ExceptionHelpers.h"
#include "JSFunction.h"
@@ -182,7 +182,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exe
return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested property names of a value that is not an object.")));
PropertyNameArray properties(exec);
asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, IncludeDontEnumProperties);
- JSArray* names = constructEmptyArray(exec);
+ JSArray* names = constructEmptyArray(exec, 0);
size_t numProperties = properties.size();
for (size_t i = 0; i < numProperties; i++)
names->push(exec, jsOwnedString(exec, properties[i].string()));
@@ -196,7 +196,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested keys of a value that is not an object.")));
PropertyNameArray properties(exec);
asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, ExcludeDontEnumProperties);
- JSArray* keys = constructEmptyArray(exec);
+ JSArray* keys = constructEmptyArray(exec, 0);
size_t numProperties = properties.size();
for (size_t i = 0; i < numProperties; i++)
keys->push(exec, jsOwnedString(exec, properties[i].string()));
diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h
index 01df7e98c..ed14e895f 100644
--- a/Source/JavaScriptCore/runtime/Operations.h
+++ b/Source/JavaScriptCore/runtime/Operations.h
@@ -26,7 +26,7 @@
#include "Interpreter.h"
#include "JSProxy.h"
#include "JSString.h"
-#include "JSValueInlineMethods.h"
+#include "JSValueInlines.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
index ce9c2d2db..19f3b81ad 100644
--- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "RegExpMatchesArray.h"
-#include "ButterflyInlineMethods.h"
+#include "ButterflyInlines.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp
index 35de40912..00dd1ed74 100644
--- a/Source/JavaScriptCore/runtime/RegExpObject.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp
@@ -21,8 +21,8 @@
#include "config.h"
#include "RegExpObject.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
+#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "ExceptionHelpers.h"
#include "JSArray.h"
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp
index 5aafe8bb3..93009d806 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp
@@ -22,9 +22,9 @@
#include "config.h"
#include "StringPrototype.h"
-#include "ButterflyInlineMethods.h"
+#include "ButterflyInlines.h"
#include "CachedCall.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "Executable.h"
#include "JSGlobalObjectFunctions.h"
@@ -870,7 +870,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
return JSValue::encode(jsNull());
}
- return JSValue::encode(constructArray(exec, list));
+ return JSValue::encode(constructArray(exec, static_cast<ArrayAllocationProfile*>(0), list));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec)
@@ -973,7 +973,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
// 3. Let A be a new array created as if by the expression new Array()
// where Array is the standard built-in constructor with that name.
- JSArray* result = constructEmptyArray(exec);
+ JSArray* result = constructEmptyArray(exec, 0);
// 4. Let lengthA be 0.
unsigned resultLength = 0;
@@ -1388,7 +1388,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec)
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
JSValue a0 = exec->argument(0);
- return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", a0.toString(exec)->value(exec), "\">", s, "</font>"));
+ String color = a0.toWTFString(exec);
+ color.replaceWithLiteral('"', "&quot;");
+
+ return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", color, "\">", s, "</font>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
@@ -1433,7 +1436,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
return JSValue::encode(jsNontrivialString(exec, impl));
}
- return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", a0.toString(exec)->value(exec), "\">", s, "</font>"));
+ String fontSize = a0.toWTFString(exec);
+ fontSize.replaceWithLiteral('"', "&quot;");
+
+ return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", fontSize, "\">", s, "</font>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec)
@@ -1443,7 +1449,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec)
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
JSValue a0 = exec->argument(0);
- return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", a0.toString(exec)->value(exec), "\">", s, "</a>"));
+ String anchor = a0.toWTFString(exec);
+ anchor.replaceWithLiteral('"', "&quot;");
+
+ return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", anchor, "\">", s, "</a>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
@@ -1453,7 +1462,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
JSValue a0 = exec->argument(0);
- String linkText = a0.toString(exec)->value(exec);
+ String linkText = a0.toWTFString(exec);
+ linkText.replaceWithLiteral('"', "&quot;");
unsigned linkTextSize = linkText.length();
unsigned stringSize = s.length();
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index e733c7e23..e930c022a 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -543,12 +543,13 @@ Structure* Structure::nonPropertyTransition(JSGlobalData& globalData, Structure*
unsigned attributes = toAttributes(transitionKind);
IndexingType indexingType = newIndexingType(structure->indexingTypeIncludingHistory(), transitionKind);
- JSGlobalObject* globalObject = structure->globalObject();
- if (structure == globalObject->arrayStructure()) {
- Structure* transition = globalObject->arrayStructureWithArrayStorage();
- if (transition->indexingTypeIncludingHistory() == indexingType) {
- structure->notifyTransitionFromThisStructure();
- return transition;
+ if (JSGlobalObject* globalObject = structure->m_globalObject.get()) {
+ if (globalObject->isOriginalArrayStructure(structure)) {
+ Structure* result = globalObject->originalArrayStructureForIndexingType(indexingType);
+ if (result->indexingTypeIncludingHistory() == indexingType) {
+ structure->notifyTransitionFromThisStructure();
+ return result;
+ }
}
}
diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
index 3ab7b2014..5291ed540 100644
--- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h
+++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
@@ -43,6 +43,9 @@ static const unsigned FirstInternalAttribute = 1 << 6; // Use for transitions th
// Support for attributes used to indicate transitions not related to properties.
// If any of these are used, the string portion of the key should be 0.
enum NonPropertyTransition {
+ AllocateUndecided,
+ AllocateInt32,
+ AllocateDouble,
AllocateContiguous,
AllocateArrayStorage,
AllocateSlowPutArrayStorage,
@@ -58,14 +61,23 @@ inline unsigned toAttributes(NonPropertyTransition transition)
inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition transition)
{
switch (transition) {
- case AllocateContiguous:
+ case AllocateUndecided:
ASSERT(!hasIndexedProperties(oldType));
- return oldType | ContiguousShape;
+ return oldType | UndecidedShape;
+ case AllocateInt32:
+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType));
+ return (oldType & ~IndexingShapeMask) | Int32Shape;
+ case AllocateDouble:
+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType));
+ return (oldType & ~IndexingShapeMask) | DoubleShape;
+ case AllocateContiguous:
+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType));
+ return (oldType & ~IndexingShapeMask) | ContiguousShape;
case AllocateArrayStorage:
- ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType));
+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType));
return (oldType & ~IndexingShapeMask) | ArrayStorageShape;
case AllocateSlowPutArrayStorage:
- ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType));
+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType) || hasContiguous(oldType));
return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape;
case SwitchToSlowPutArrayStorage:
ASSERT(hasFastArrayStorage(oldType));