summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore')
-rw-r--r--Source/JavaScriptCore/API/JSObjectRef.cpp8
-rw-r--r--Source/JavaScriptCore/CMakeLists.txt51
-rw-r--r--Source/JavaScriptCore/ChangeLog2210
-rw-r--r--Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig4
-rw-r--r--Source/JavaScriptCore/Configurations/Version.xcconfig2
-rw-r--r--Source/JavaScriptCore/GNUmakefile.list.am24
-rwxr-xr-xSource/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def9
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj42
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj96
-rw-r--r--Source/JavaScriptCore/Target.pri4
-rw-r--r--Source/JavaScriptCore/assembler/ARMv7Assembler.h112
-rw-r--r--Source/JavaScriptCore/assembler/AbstractMacroAssembler.h7
-rw-r--r--Source/JavaScriptCore/assembler/LinkBuffer.cpp23
-rw-r--r--Source/JavaScriptCore/assembler/LinkBuffer.h14
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerARM.h13
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h24
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h14
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerX86.h34
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h4
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h27
-rw-r--r--Source/JavaScriptCore/assembler/RepatchBuffer.h28
-rw-r--r--Source/JavaScriptCore/assembler/SH4Assembler.h2
-rw-r--r--Source/JavaScriptCore/assembler/X86Assembler.h78
-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/CallLinkInfo.cpp2
-rw-r--r--Source/JavaScriptCore/bytecode/CallLinkInfo.h9
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.cpp569
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.h54
-rw-r--r--Source/JavaScriptCore/bytecode/DFGExitProfile.h2
-rw-r--r--Source/JavaScriptCore/bytecode/GetByIdStatus.cpp32
-rw-r--r--Source/JavaScriptCore/bytecode/GetByIdStatus.h8
-rw-r--r--Source/JavaScriptCore/bytecode/Instruction.h5
-rw-r--r--Source/JavaScriptCore/bytecode/Opcode.cpp24
-rw-r--r--Source/JavaScriptCore/bytecode/Opcode.h9
-rw-r--r--Source/JavaScriptCore/bytecode/Operands.h12
-rw-r--r--Source/JavaScriptCore/bytecode/PutByIdStatus.cpp73
-rw-r--r--Source/JavaScriptCore/bytecode/PutByIdStatus.h13
-rw-r--r--Source/JavaScriptCore/bytecode/SamplingTool.cpp60
-rw-r--r--Source/JavaScriptCore/bytecode/SpeculatedType.h26
-rw-r--r--Source/JavaScriptCore/bytecode/StructureStubInfo.h2
-rw-r--r--Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp19
-rw-r--r--Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h11
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp25
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h1
-rw-r--r--Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp10
-rw-r--r--Source/JavaScriptCore/debugger/Debugger.cpp2
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp311
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.h50
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractValue.h26
-rw-r--r--Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp30
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.cpp295
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.h78
-rw-r--r--Source/JavaScriptCore/dfg/DFGBasicBlock.h3
-rw-r--r--Source/JavaScriptCore/dfg/DFGBranchDirection.h88
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp191
-rw-r--r--Source/JavaScriptCore/dfg/DFGCCallHelpers.h105
-rw-r--r--Source/JavaScriptCore/dfg/DFGCFAPhase.cpp22
-rw-r--r--Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp50
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp16
-rw-r--r--Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h4
-rw-r--r--Source/JavaScriptCore/dfg/DFGCapabilities.cpp6
-rw-r--r--Source/JavaScriptCore/dfg/DFGCapabilities.h1
-rw-r--r--Source/JavaScriptCore/dfg/DFGCommon.h15
-rw-r--r--Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp237
-rw-r--r--Source/JavaScriptCore/dfg/DFGDisassembler.cpp11
-rw-r--r--Source/JavaScriptCore/dfg/DFGDriver.cpp8
-rw-r--r--Source/JavaScriptCore/dfg/DFGFixupPhase.cpp108
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.cpp149
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h17
-rw-r--r--Source/JavaScriptCore/dfg/DFGJITCompiler.cpp5
-rw-r--r--Source/JavaScriptCore/dfg/DFGJITCompiler.h8
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h111
-rw-r--r--Source/JavaScriptCore/dfg/DFGNodeFlags.cpp6
-rw-r--r--Source/JavaScriptCore/dfg/DFGNodeFlags.h9
-rw-r--r--Source/JavaScriptCore/dfg/DFGNodeType.h6
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSREntry.cpp24
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp2
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp10
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp32
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp131
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.h12
-rw-r--r--Source/JavaScriptCore/dfg/DFGPhase.cpp4
-rw-r--r--Source/JavaScriptCore/dfg/DFGPhase.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp188
-rw-r--r--Source/JavaScriptCore/dfg/DFGRegisterBank.h34
-rw-r--r--Source/JavaScriptCore/dfg/DFGRepatch.cpp172
-rw-r--r--Source/JavaScriptCore/dfg/DFGRepatch.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGScoreBoard.h20
-rw-r--r--Source/JavaScriptCore/dfg/DFGSlowPathGenerator.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp260
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h56
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp558
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp390
-rw-r--r--Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp10
-rw-r--r--Source/JavaScriptCore/dfg/DFGThunks.cpp12
-rw-r--r--Source/JavaScriptCore/dfg/DFGThunks.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGValidate.cpp32
-rw-r--r--Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp6
-rw-r--r--Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp14
-rw-r--r--Source/JavaScriptCore/disassembler/Disassembler.cpp43
-rw-r--r--Source/JavaScriptCore/disassembler/Disassembler.h4
-rw-r--r--Source/JavaScriptCore/heap/BlockAllocator.cpp2
-rw-r--r--Source/JavaScriptCore/heap/BlockAllocator.h20
-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.cpp7
-rw-r--r--Source/JavaScriptCore/heap/GCThreadSharedData.h2
-rw-r--r--Source/JavaScriptCore/heap/HandleStack.cpp2
-rw-r--r--Source/JavaScriptCore/heap/Heap.cpp8
-rw-r--r--Source/JavaScriptCore/heap/Heap.h2
-rw-r--r--Source/JavaScriptCore/heap/HeapRootVisitor.h2
-rw-r--r--Source/JavaScriptCore/heap/HeapStatistics.cpp38
-rw-r--r--Source/JavaScriptCore/heap/HeapStatistics.h4
-rw-r--r--Source/JavaScriptCore/heap/JITStubRoutineSet.h3
-rw-r--r--Source/JavaScriptCore/heap/MarkStack.cpp154
-rw-r--r--Source/JavaScriptCore/heap/MarkStack.h59
-rw-r--r--Source/JavaScriptCore/heap/MarkStackInlines.h (renamed from Source/JavaScriptCore/heap/MarkStackInlineMethods.h)40
-rw-r--r--Source/JavaScriptCore/heap/MarkedBlock.h2
-rw-r--r--Source/JavaScriptCore/heap/SlotVisitor.cpp11
-rw-r--r--Source/JavaScriptCore/heap/SlotVisitor.h5
-rw-r--r--Source/JavaScriptCore/heap/SlotVisitorInlines.h (renamed from Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h)17
-rw-r--r--Source/JavaScriptCore/heap/Weak.h5
-rw-r--r--Source/JavaScriptCore/interpreter/CallFrame.cpp2
-rw-r--r--Source/JavaScriptCore/interpreter/Interpreter.cpp38
-rw-r--r--Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp62
-rw-r--r--Source/JavaScriptCore/jit/ClosureCallStubRoutine.h66
-rw-r--r--Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp4
-rw-r--r--Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h5
-rw-r--r--Source/JavaScriptCore/jit/HostCallReturnValue.cpp2
-rw-r--r--Source/JavaScriptCore/jit/JIT.cpp37
-rw-r--r--Source/JavaScriptCore/jit/JIT.h21
-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/JITDisassembler.cpp101
-rw-r--r--Source/JavaScriptCore/jit/JITDisassembler.h78
-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.cpp18
-rw-r--r--Source/JavaScriptCore/jit/JITOpcodes32_64.cpp14
-rw-r--r--Source/JavaScriptCore/jit/JITPropertyAccess.cpp90
-rw-r--r--Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp73
-rw-r--r--Source/JavaScriptCore/jit/JITStubRoutine.h8
-rw-r--r--Source/JavaScriptCore/jit/JITStubs.cpp39
-rw-r--r--Source/JavaScriptCore/jit/JITStubs.h2
-rw-r--r--Source/JavaScriptCore/jit/JumpReplacementWatchpoint.cpp2
-rw-r--r--Source/JavaScriptCore/jsc.cpp6
-rw-r--r--Source/JavaScriptCore/llint/LLIntData.cpp16
-rw-r--r--Source/JavaScriptCore/llint/LLIntExceptions.cpp6
-rw-r--r--Source/JavaScriptCore/llint/LLIntSlowPaths.cpp64
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter.asm17
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm101
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter64.asm96
-rw-r--r--Source/JavaScriptCore/offlineasm/x86.rb34
-rw-r--r--Source/JavaScriptCore/profiler/Profile.cpp10
-rw-r--r--Source/JavaScriptCore/profiler/ProfileNode.cpp18
-rw-r--r--Source/JavaScriptCore/profiler/ProfileNode.h1
-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.cpp23
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.h32
-rw-r--r--Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h38
-rw-r--r--Source/JavaScriptCore/runtime/BooleanConstructor.h48
-rw-r--r--Source/JavaScriptCore/runtime/BooleanObject.h52
-rw-r--r--Source/JavaScriptCore/runtime/BooleanPrototype.h46
-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/CallData.h42
-rw-r--r--Source/JavaScriptCore/runtime/ClassInfo.h206
-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.h3
-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/JSBoundFunction.cpp7
-rw-r--r--Source/JavaScriptCore/runtime/JSBoundFunction.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.h3
-rw-r--r--Source/JavaScriptCore/runtime/JSFunction.cpp19
-rw-r--r--Source/JavaScriptCore/runtime/JSFunction.h24
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.cpp10
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.cpp39
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.h83
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSLock.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp677
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h235
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.cpp16
-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.h21
-rw-r--r--Source/JavaScriptCore/runtime/Options.h2
-rw-r--r--Source/JavaScriptCore/runtime/RegExp.cpp12
-rw-r--r--Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/SamplingCounter.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/StringPrototype.cpp26
-rw-r--r--Source/JavaScriptCore/runtime/Structure.cpp69
-rw-r--r--Source/JavaScriptCore/runtime/Structure.h9
-rw-r--r--Source/JavaScriptCore/runtime/StructureTransitionTable.h20
-rw-r--r--Source/JavaScriptCore/tools/CodeProfile.cpp6
-rw-r--r--Source/JavaScriptCore/tools/ProfileTreeNode.h4
-rw-r--r--Source/JavaScriptCore/yarr/YarrInterpreter.cpp6
220 files changed, 9873 insertions, 2628 deletions
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..a77e9e451 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
@@ -103,6 +104,8 @@ SET(JavaScriptCore_SOURCES
dfg/DFGVariableEventStream.cpp
dfg/DFGValidate.cpp
dfg/DFGVirtualRegisterAllocationPhase.cpp
+
+ disassembler/Disassembler.cpp
heap/BlockAllocator.cpp
heap/CopiedSpace.cpp
@@ -138,6 +141,7 @@ SET(JavaScriptCore_SOURCES
interpreter/JSStack.cpp
interpreter/VMInspector.cpp
+ jit/ClosureCallStubRoutine.cpp
jit/ExecutableAllocator.cpp
jit/HostCallReturnValue.cpp
jit/GCAwareJITStubRoutine.cpp
@@ -146,6 +150,7 @@ SET(JavaScriptCore_SOURCES
jit/JITCall32_64.cpp
jit/JITCall.cpp
jit/JIT.cpp
+ jit/JITDisassembler.cpp
jit/JITExceptions.cpp
jit/JITOpcodes32_64.cpp
jit/JITOpcodes.cpp
@@ -353,11 +358,18 @@ IF (ENABLE_LLINT)
)
TARGET_LINK_LIBRARIES(LLIntOffsetsExtractor ${WTF_LIBRARY_NAME})
+ # The build system will execute asm.rb every time LLIntOffsetsExtractor's mtime is newer than
+ # LLIntAssembly.h's mtime. The problem we have here is: asm.rb has some built-in optimization
+ # that generates a checksum of the LLIntOffsetsExtractor binary, if the checksum of the new
+ # LLIntOffsetsExtractor matches, no output is generated. To make this target consistent and avoid
+ # running this command for every build, we artificially update LLIntAssembly.h's mtime (using touch)
+ # after every asm.rb run.
ADD_CUSTOM_COMMAND(
OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntAssembly.h
MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/offlineasm/asm.rb
DEPENDS LLIntOffsetsExtractor ${LLINT_ASM} ${OFFLINE_ASM}
COMMAND ${RUBY_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/offlineasm/asm.rb ${JAVASCRIPTCORE_DIR}/llint/LowLevelInterpreter.asm $<TARGET_FILE:LLIntOffsetsExtractor> ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntAssembly.h
+ COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntAssembly.h
VERBATIM)
# The explanation for not making LLIntAssembly.h part of the OBJECT_DEPENDS property of some of
@@ -385,6 +397,43 @@ FOREACH (_file ${JavaScriptCore_LUT_FILES})
LIST(APPEND JavaScriptCore_HEADERS ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/${_name}.lut.h)
ENDFOREACH ()
+SET (JavaScriptCore_FORWARDING_HEADERS_DIRECTORIES
+ assembler
+ bytecode
+ collector/handles
+ debugger
+ heap
+ interpreter
+ jit
+ llint
+ parser
+ profiler
+ runtime
+ yarr
+)
+
+SET (JavaScriptCore_FORWARDING_HEADERS_FILES
+ API/APICast.h
+ API/APIShims.h
+ API/JavaScript.h
+ API/JSBase.h
+ API/JSContextRef.h
+ API/JSContextRefPrivate.h
+ API/JSObjectRef.h
+ API/JSObjectRefPrivate.h
+ API/JSStringRef.h
+ API/JSStringRefCF.h
+ API/JSStringRefBSTR.h
+ API/JSValueRef.h
+ API/JavaScriptCore.h
+ API/JSRetainPtr.h
+ API/JSWeakObjectMapRefInternal.h
+ API/JSWeakObjectMapRefPrivate.h
+ API/JSRetainPtr.h
+ API/OpaqueJSString.h
+ API/WebKitAvailability.h
+)
+
# GENERATOR 1-B: particular LUT creator (for 1 file only)
GENERATE_HASH_LUT(${JAVASCRIPTCORE_DIR}/parser/Keywords.table ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/Lexer.lut.h MAIN_DEPENDENCY)
@@ -423,6 +472,8 @@ ENDIF ()
WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS()
+WEBKIT_CREATE_FORWARDING_HEADERS(JavaScriptCore DIRECTORIES ${JavaScriptCore_FORWARDING_HEADERS_DIRECTORIES} FILES ${JavaScriptCore_FORWARDING_HEADERS_FILES})
+
ADD_SUBDIRECTORY(shell)
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 3c0e4ddae..aa92eade1 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,1569 @@
+2012-11-21 Filip Pizlo <fpizlo@apple.com>
+
+ Rename dataLog() and dataLogV() to dataLogF() and dataLogFV()
+ https://bugs.webkit.org/show_bug.cgi?id=103001
+
+ Rubber stamped by Dan Bernstein.
+
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+ * assembler/LinkBuffer.cpp:
+ (JSC::LinkBuffer::finalizeCodeWithDisassembly):
+ (JSC::LinkBuffer::dumpLinkStatistics):
+ (JSC::LinkBuffer::dumpCode):
+ * assembler/LinkBuffer.h:
+ (JSC):
+ * assembler/SH4Assembler.h:
+ (JSC::SH4Assembler::vprintfStdoutInstr):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dumpBytecodeCommentAndNewLine):
+ (JSC::CodeBlock::printUnaryOp):
+ (JSC::CodeBlock::printBinaryOp):
+ (JSC::CodeBlock::printConditionalJump):
+ (JSC::CodeBlock::printGetByIdOp):
+ (JSC::dumpStructure):
+ (JSC::dumpChain):
+ (JSC::CodeBlock::printGetByIdCacheStatus):
+ (JSC::CodeBlock::printCallOp):
+ (JSC::CodeBlock::printPutByIdOp):
+ (JSC::CodeBlock::printStructure):
+ (JSC::CodeBlock::printStructures):
+ (JSC::CodeBlock::dump):
+ (JSC::CodeBlock::dumpStatistics):
+ (JSC::CodeBlock::finalizeUnconditionally):
+ (JSC::CodeBlock::resetStubInternal):
+ (JSC::CodeBlock::reoptimize):
+ (JSC::ProgramCodeBlock::jettison):
+ (JSC::EvalCodeBlock::jettison):
+ (JSC::FunctionCodeBlock::jettison):
+ (JSC::CodeBlock::shouldOptimizeNow):
+ (JSC::CodeBlock::tallyFrequentExitSites):
+ (JSC::CodeBlock::dumpValueProfiles):
+ * bytecode/Opcode.cpp:
+ (JSC::OpcodeStats::~OpcodeStats):
+ * bytecode/SamplingTool.cpp:
+ (JSC::SamplingFlags::stop):
+ (JSC::SamplingRegion::dumpInternal):
+ (JSC::SamplingTool::dump):
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::initialize):
+ (JSC::DFG::AbstractState::endBasicBlock):
+ (JSC::DFG::AbstractState::mergeStateAtTail):
+ (JSC::DFG::AbstractState::mergeToSuccessors):
+ * dfg/DFGAbstractValue.h:
+ (JSC::DFG::AbstractValue::dump):
+ * dfg/DFGArgumentsSimplificationPhase.cpp:
+ (JSC::DFG::ArgumentsSimplificationPhase::run):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::injectLazyOperandSpeculation):
+ (JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
+ (JSC::DFG::ByteCodeParser::getArrayModeAndEmitChecks):
+ (JSC::DFG::ByteCodeParser::makeSafe):
+ (JSC::DFG::ByteCodeParser::makeDivSafe):
+ (JSC::DFG::ByteCodeParser::handleCall):
+ (JSC::DFG::ByteCodeParser::handleInlining):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ (JSC::DFG::ByteCodeParser::processPhiStack):
+ (JSC::DFG::ByteCodeParser::linkBlock):
+ (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
+ (JSC::DFG::ByteCodeParser::parseCodeBlock):
+ (JSC::DFG::ByteCodeParser::parse):
+ * dfg/DFGCFAPhase.cpp:
+ (JSC::DFG::CFAPhase::performBlockCFA):
+ (JSC::DFG::CFAPhase::performForwardCFA):
+ * dfg/DFGCFGSimplificationPhase.cpp:
+ (JSC::DFG::CFGSimplificationPhase::run):
+ (JSC::DFG::CFGSimplificationPhase::fixPossibleGetLocal):
+ (JSC::DFG::CFGSimplificationPhase::fixPhis):
+ (JSC::DFG::CFGSimplificationPhase::fixJettisonedPredecessors):
+ (JSC::DFG::CFGSimplificationPhase::removePotentiallyDeadPhiReference):
+ (JSC::DFG::CFGSimplificationPhase::mergeBlocks):
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::endIndexForPureCSE):
+ (JSC::DFG::CSEPhase::setReplacement):
+ (JSC::DFG::CSEPhase::eliminate):
+ (JSC::DFG::CSEPhase::performNodeCSE):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::debugFail):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ (JSC::DFG::ConstantFoldingPhase::paintUnreachableCode):
+ * dfg/DFGDisassembler.cpp:
+ (JSC::DFG::Disassembler::dump):
+ * dfg/DFGDriver.cpp:
+ (JSC::DFG::compile):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ (JSC::DFG::FixupPhase::fixDoubleEdge):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::printWhiteSpace):
+ (JSC::DFG::Graph::dumpCodeOrigin):
+ (JSC::DFG::Graph::dump):
+ (JSC::DFG::Graph::dumpBlockHeader):
+ (JSC::DFG::Graph::predictArgumentTypes):
+ * dfg/DFGJITCompiler.cpp:
+ (JSC::DFG::JITCompiler::link):
+ * dfg/DFGOSREntry.cpp:
+ (JSC::DFG::prepareOSREntry):
+ * dfg/DFGOSRExitCompiler.cpp:
+ * dfg/DFGOSRExitCompiler32_64.cpp:
+ (JSC::DFG::OSRExitCompiler::compileExit):
+ * dfg/DFGOSRExitCompiler64.cpp:
+ (JSC::DFG::OSRExitCompiler::compileExit):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGPhase.cpp:
+ (JSC::DFG::Phase::beginPhase):
+ * dfg/DFGPhase.h:
+ (JSC::DFG::runAndLog):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ (JSC::DFG::PredictionPropagationPhase::propagateForward):
+ (JSC::DFG::PredictionPropagationPhase::propagateBackward):
+ (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
+ * dfg/DFGRegisterBank.h:
+ (JSC::DFG::RegisterBank::dump):
+ * dfg/DFGScoreBoard.h:
+ (JSC::DFG::ScoreBoard::use):
+ (JSC::DFG::ScoreBoard::dump):
+ * dfg/DFGSlowPathGenerator.h:
+ (JSC::DFG::SlowPathGenerator::generate):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::terminateSpeculativeExecution):
+ (JSC::DFG::SpeculativeJIT::terminateSpeculativeExecutionWithConditionalDirection):
+ (JSC::DFG::SpeculativeJIT::runSlowPathGenerators):
+ (JSC::DFG::SpeculativeJIT::dump):
+ (JSC::DFG::SpeculativeJIT::checkConsistency):
+ (JSC::DFG::SpeculativeJIT::compile):
+ (JSC::DFG::SpeculativeJIT::checkGeneratedTypeForToInt32):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
+ * dfg/DFGStructureCheckHoistingPhase.cpp:
+ (JSC::DFG::StructureCheckHoistingPhase::run):
+ * dfg/DFGValidate.cpp:
+ (Validate):
+ (JSC::DFG::Validate::reportValidationContext):
+ (JSC::DFG::Validate::dumpData):
+ (JSC::DFG::Validate::dumpGraphIfAppropriate):
+ * dfg/DFGVariableEventStream.cpp:
+ (JSC::DFG::VariableEventStream::logEvent):
+ (JSC::DFG::VariableEventStream::reconstruct):
+ * dfg/DFGVirtualRegisterAllocationPhase.cpp:
+ (JSC::DFG::VirtualRegisterAllocationPhase::run):
+ * heap/Heap.cpp:
+ * heap/HeapStatistics.cpp:
+ (JSC::HeapStatistics::logStatistics):
+ (JSC::HeapStatistics::showObjectStatistics):
+ * heap/MarkStack.h:
+ * heap/MarkedBlock.h:
+ * heap/SlotVisitor.cpp:
+ (JSC::SlotVisitor::validate):
+ * interpreter/CallFrame.cpp:
+ (JSC::CallFrame::dumpCaller):
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::dumpRegisters):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ (JSC::JIT::privateCompileSlowCases):
+ (JSC::JIT::privateCompile):
+ * jit/JITDisassembler.cpp:
+ (JSC::JITDisassembler::dump):
+ (JSC::JITDisassembler::dumpForInstructions):
+ * jit/JITStubRoutine.h:
+ (JSC):
+ * jit/JITStubs.cpp:
+ (JSC::DEFINE_STUB_FUNCTION):
+ * jit/JumpReplacementWatchpoint.cpp:
+ (JSC::JumpReplacementWatchpoint::fireInternal):
+ * llint/LLIntExceptions.cpp:
+ (JSC::LLInt::interpreterThrowInCaller):
+ (JSC::LLInt::returnToThrow):
+ (JSC::LLInt::callToThrow):
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::llint_trace_operand):
+ (JSC::LLInt::llint_trace_value):
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ (JSC::LLInt::traceFunctionPrologue):
+ (JSC::LLInt::jitCompileAndSetHeuristics):
+ (JSC::LLInt::entryOSR):
+ (JSC::LLInt::handleHostCall):
+ (JSC::LLInt::setUpCall):
+ * profiler/Profile.cpp:
+ (JSC::Profile::debugPrintData):
+ (JSC::Profile::debugPrintDataSampleStyle):
+ * profiler/ProfileNode.cpp:
+ (JSC::ProfileNode::debugPrintData):
+ (JSC::ProfileNode::debugPrintDataSampleStyle):
+ * runtime/JSGlobalData.cpp:
+ (JSC::JSGlobalData::dumpRegExpTrace):
+ * runtime/RegExp.cpp:
+ (JSC::RegExp::matchCompareWithInterpreter):
+ * runtime/SamplingCounter.cpp:
+ (JSC::AbstractSamplingCounter::dump):
+ * runtime/Structure.cpp:
+ (JSC::Structure::dumpStatistics):
+ (JSC::PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger):
+ * tools/CodeProfile.cpp:
+ (JSC::CodeProfile::report):
+ * tools/ProfileTreeNode.h:
+ (JSC::ProfileTreeNode::dumpInternal):
+ * yarr/YarrInterpreter.cpp:
+ (JSC::Yarr::ByteCompiler::dumpDisjunction):
+
+2012-11-21 Filip Pizlo <fpizlo@apple.com>
+
+ It should be possible to say disassemble(stuff) instead of having to say if (!tryToDisassemble(stuff)) dataLog("I failed")
+ https://bugs.webkit.org/show_bug.cgi?id=103010
+
+ Reviewed by Anders Carlsson.
+
+ You can still say tryToDisassemble(), which will tell you if it failed; you can then
+ decide what to do instead. But it's better to say disassemble(), which will just print
+ the instruction ranges if tryToDisassemble() failed. This is particularly appropriate
+ since that's what all previous users of tryToDisassemble() would have done in some
+ form or another.
+
+ * CMakeLists.txt:
+ * GNUmakefile.list.am:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * Target.pri:
+ * assembler/LinkBuffer.cpp:
+ (JSC::LinkBuffer::finalizeCodeWithDisassembly):
+ * dfg/DFGDisassembler.cpp:
+ (JSC::DFG::Disassembler::dumpDisassembly):
+ * disassembler/Disassembler.cpp: Added.
+ (JSC):
+ (JSC::disassemble):
+ * disassembler/Disassembler.h:
+ (JSC):
+ * jit/JITDisassembler.cpp:
+ (JSC::JITDisassembler::dumpDisassembly):
+
+2012-11-21 Filip Pizlo <fpizlo@apple.com>
+
+ dumpOperands() claims that it needs a non-const Operands& when that is completely false
+ https://bugs.webkit.org/show_bug.cgi?id=103005
+
+ Reviewed by Eric Carlson.
+
+ * bytecode/Operands.h:
+ (JSC::dumpOperands):
+ (JSC):
+
+2012-11-20 Filip Pizlo <fpizlo@apple.com>
+
+ Baseline JIT's disassembly should be just as pretty as the DFG's
+ https://bugs.webkit.org/show_bug.cgi?id=102873
+
+ Reviewed by Sam Weinig.
+
+ Integrated the CodeBlock's bytecode dumper with the JIT's disassembler. Also fixed
+ some type goof-ups (instructions are not in a Vector<Instruction> so using a Vector
+ iterator makes no sense) and stream-lined some things (you don't actually need a
+ full-fledged ExecState* to dump bytecode).
+
+ * CMakeLists.txt:
+ * GNUmakefile.list.am:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * Target.pri:
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::printUnaryOp):
+ (JSC::CodeBlock::printBinaryOp):
+ (JSC::CodeBlock::printConditionalJump):
+ (JSC::CodeBlock::printGetByIdOp):
+ (JSC::CodeBlock::printCallOp):
+ (JSC::CodeBlock::printPutByIdOp):
+ (JSC::CodeBlock::dump):
+ (JSC):
+ (JSC::CodeBlock::CodeBlock):
+ * bytecode/CodeBlock.h:
+ (CodeBlock):
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::dumpCallFrame):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ (JSC::JIT::privateCompileSlowCases):
+ (JSC::JIT::privateCompile):
+ * jit/JIT.h:
+ (JIT):
+ * jit/JITDisassembler.cpp: Added.
+ (JSC):
+ (JSC::JITDisassembler::JITDisassembler):
+ (JSC::JITDisassembler::~JITDisassembler):
+ (JSC::JITDisassembler::dump):
+ (JSC::JITDisassembler::dumpForInstructions):
+ (JSC::JITDisassembler::dumpDisassembly):
+ * jit/JITDisassembler.h: Added.
+ (JSC):
+ (JITDisassembler):
+ (JSC::JITDisassembler::setStartOfCode):
+ (JSC::JITDisassembler::setForBytecodeMainPath):
+ (JSC::JITDisassembler::setForBytecodeSlowPath):
+ (JSC::JITDisassembler::setEndOfSlowPath):
+ (JSC::JITDisassembler::setEndOfCode):
+
+2012-11-21 Daniel Bates <dbates@webkit.org>
+
+ JavaScript fails to concatenate large strings
+ <https://bugs.webkit.org/show_bug.cgi?id=102963>
+
+ Reviewed by Michael Saboff.
+
+ Fixes an issue where we inadvertently didn't check the length of
+ a JavaScript string for overflow.
+
+ * runtime/Operations.h:
+ (JSC::jsString):
+ (JSC::jsStringFromArguments):
+
+2012-11-20 Filip Pizlo <fpizlo@apple.com>
+
+ DFG should be able to cache closure calls (part 2/2)
+ https://bugs.webkit.org/show_bug.cgi?id=102662
+
+ Reviewed by Gavin Barraclough.
+
+ Added caching of calls where the JSFunction* varies, but the Structure* and ExecutableBase*
+ stay the same. This is accomplished by replacing the branch that compares against a constant
+ JSFunction* with a jump to a closure call stub. The closure call stub contains a fast path,
+ and jumps slow directly to the virtual call thunk.
+
+ Looks like a 1% win on V8v7.
+
+ * CMakeLists.txt:
+ * GNUmakefile.list.am:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * Target.pri:
+ * bytecode/CallLinkInfo.cpp:
+ (JSC::CallLinkInfo::unlink):
+ * bytecode/CallLinkInfo.h:
+ (CallLinkInfo):
+ (JSC::CallLinkInfo::isLinked):
+ (JSC::getCallLinkInfoBytecodeIndex):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::finalizeUnconditionally):
+ (JSC):
+ (JSC::CodeBlock::findClosureCallForReturnPC):
+ (JSC::CodeBlock::bytecodeOffset):
+ (JSC::CodeBlock::codeOriginForReturn):
+ * bytecode/CodeBlock.h:
+ (JSC::CodeBlock::getCallLinkInfo):
+ (CodeBlock):
+ (JSC::CodeBlock::isIncomingCallAlreadyLinked):
+ * dfg/DFGJITCompiler.cpp:
+ (JSC::DFG::JITCompiler::link):
+ * dfg/DFGJITCompiler.h:
+ (JSC::DFG::JITCompiler::addJSCall):
+ (JSC::DFG::JITCompiler::JSCallRecord::JSCallRecord):
+ (JSCallRecord):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGRepatch.cpp:
+ (JSC::DFG::linkSlowFor):
+ (DFG):
+ (JSC::DFG::dfgLinkFor):
+ (JSC::DFG::dfgLinkSlowFor):
+ (JSC::DFG::dfgLinkClosureCall):
+ * dfg/DFGRepatch.h:
+ (DFG):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ * dfg/DFGThunks.cpp:
+ (DFG):
+ (JSC::DFG::linkClosureCallThunkGenerator):
+ * dfg/DFGThunks.h:
+ (DFG):
+ * heap/Heap.h:
+ (Heap):
+ (JSC::Heap::jitStubRoutines):
+ * heap/JITStubRoutineSet.h:
+ (JSC::JITStubRoutineSet::size):
+ (JSC::JITStubRoutineSet::at):
+ (JITStubRoutineSet):
+ * jit/ClosureCallStubRoutine.cpp: Added.
+ (JSC):
+ (JSC::ClosureCallStubRoutine::ClosureCallStubRoutine):
+ (JSC::ClosureCallStubRoutine::~ClosureCallStubRoutine):
+ (JSC::ClosureCallStubRoutine::markRequiredObjectsInternal):
+ * jit/ClosureCallStubRoutine.h: Added.
+ (JSC):
+ (ClosureCallStubRoutine):
+ (JSC::ClosureCallStubRoutine::structure):
+ (JSC::ClosureCallStubRoutine::executable):
+ (JSC::ClosureCallStubRoutine::codeOrigin):
+ * jit/GCAwareJITStubRoutine.cpp:
+ (JSC::GCAwareJITStubRoutine::GCAwareJITStubRoutine):
+ * jit/GCAwareJITStubRoutine.h:
+ (GCAwareJITStubRoutine):
+ (JSC::GCAwareJITStubRoutine::isClosureCall):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompile):
+
+2012-11-20 Filip Pizlo <fpizlo@apple.com>
+
+ DFG should be able to cache closure calls (part 1/2)
+ https://bugs.webkit.org/show_bug.cgi?id=102662
+
+ Reviewed by Gavin Barraclough.
+
+ Add ability to revert a jump replacement back to
+ branchPtrWithPatch(Condition, RegisterID, TrustedImmPtr). This is meant to be
+ a mandatory piece of functionality for all assemblers. I also renamed some of
+ the functions for reverting jump replacements back to
+ patchableBranchPtrWithPatch(Condition, Address, TrustedImmPtr), so as to avoid
+ confusion.
+
+ * assembler/ARMv7Assembler.h:
+ (JSC::ARMv7Assembler::BadReg):
+ (ARMv7Assembler):
+ (JSC::ARMv7Assembler::revertJumpTo_movT3):
+ * assembler/LinkBuffer.h:
+ (JSC):
+ * assembler/MacroAssemblerARMv7.h:
+ (JSC::MacroAssemblerARMv7::startOfBranchPtrWithPatchOnRegister):
+ (MacroAssemblerARMv7):
+ (JSC::MacroAssemblerARMv7::revertJumpReplacementToBranchPtrWithPatch):
+ (JSC::MacroAssemblerARMv7::startOfPatchableBranchPtrWithPatchOnAddress):
+ * assembler/MacroAssemblerX86.h:
+ (JSC::MacroAssemblerX86::startOfBranchPtrWithPatchOnRegister):
+ (MacroAssemblerX86):
+ (JSC::MacroAssemblerX86::startOfPatchableBranchPtrWithPatchOnAddress):
+ (JSC::MacroAssemblerX86::revertJumpReplacementToBranchPtrWithPatch):
+ * assembler/MacroAssemblerX86_64.h:
+ (JSC::MacroAssemblerX86_64::startOfBranchPtrWithPatchOnRegister):
+ (JSC::MacroAssemblerX86_64::startOfPatchableBranchPtrWithPatchOnAddress):
+ (MacroAssemblerX86_64):
+ (JSC::MacroAssemblerX86_64::revertJumpReplacementToBranchPtrWithPatch):
+ * assembler/RepatchBuffer.h:
+ (JSC::RepatchBuffer::startOfBranchPtrWithPatchOnRegister):
+ (RepatchBuffer):
+ (JSC::RepatchBuffer::startOfPatchableBranchPtrWithPatchOnAddress):
+ (JSC::RepatchBuffer::revertJumpReplacementToBranchPtrWithPatch):
+ * assembler/X86Assembler.h:
+ (JSC::X86Assembler::revertJumpTo_cmpl_ir_force32):
+ (X86Assembler):
+ * dfg/DFGRepatch.cpp:
+ (JSC::DFG::replaceWithJump):
+ (JSC::DFG::dfgResetGetByID):
+ (JSC::DFG::dfgResetPutByID):
+
+2012-11-20 Yong Li <yoli@rim.com>
+
+ [ARMv7] Neither linkCall() nor linkPointer() should flush code.
+ https://bugs.webkit.org/show_bug.cgi?id=99213
+
+ Reviewed by George Staikos.
+
+ LinkBuffer doesn't need to flush code during linking. It will
+ eventually flush the whole executable. Fixing this gives >%5
+ sunspider boost (on QNX).
+
+ Also make replaceWithLoad() and replaceWithAddressComputation() flush
+ only when necessary.
+
+ * assembler/ARMv7Assembler.h:
+ (JSC::ARMv7Assembler::linkCall):
+ (JSC::ARMv7Assembler::linkPointer):
+ (JSC::ARMv7Assembler::relinkCall):
+ (JSC::ARMv7Assembler::repatchInt32):
+ (JSC::ARMv7Assembler::repatchPointer):
+ (JSC::ARMv7Assembler::replaceWithLoad): Flush only after it did write.
+ (JSC::ARMv7Assembler::replaceWithAddressComputation): Flush only after it did write.
+ (JSC::ARMv7Assembler::setInt32):
+ (JSC::ARMv7Assembler::setPointer):
+
+2012-11-19 Filip Pizlo <fpizlo@apple.com>
+
+ Remove support for ARMv7 errata from the jump code
+ https://bugs.webkit.org/show_bug.cgi?id=102759
+
+ Reviewed by Oliver Hunt.
+
+ The jump replacement code was wrong to begin with since it wasn't doing
+ a cache flush on the inserted padding. And, to my knowledge, we don't need
+ this anymore, so this patch removes all errata code from the ARMv7 port.
+
+ * assembler/ARMv7Assembler.h:
+ (JSC::ARMv7Assembler::computeJumpType):
+ (JSC::ARMv7Assembler::replaceWithJump):
+ (JSC::ARMv7Assembler::maxJumpReplacementSize):
+ (JSC::ARMv7Assembler::canBeJumpT3):
+ (JSC::ARMv7Assembler::canBeJumpT4):
+
+2012-11-19 Patrick Gansterer <paroga@webkit.org>
+
+ [CMake] Create JavaScriptCore ForwardingHeaders
+ https://bugs.webkit.org/show_bug.cgi?id=92665
+
+ Reviewed by Brent Fulgham.
+
+ When using CMake to build the Windows port, we need
+ to generate the forwarding headers with it too.
+
+ * CMakeLists.txt:
+
+2012-11-19 Kihong Kwon <kihong.kwon@samsung.com>
+
+ Add PROXIMITY_EVENTS feature
+ https://bugs.webkit.org/show_bug.cgi?id=102658
+
+ Reviewed by Kentaro Hara.
+
+ Add PROXIMITY_EVENTS feature to xcode project for JavaScriptCore.
+
+ * Configurations/FeatureDefines.xcconfig:
+
+2012-11-18 Dan Bernstein <mitz@apple.com>
+
+ Try to fix the DFG build after r135099.
+
+ * dfg/DFGCommon.h:
+ (JSC::DFG::shouldShowDisassembly):
+
+2012-11-18 Filip Pizlo <fpizlo@apple.com>
+
+ Unreviewed, build fix for !ENABLE(DFG_JIT).
+
+ * dfg/DFGCommon.h:
+ (JSC::DFG::shouldShowDisassembly):
+ (DFG):
+
+2012-11-18 Filip Pizlo <fpizlo@apple.com>
+
+ JSC should have more logging in structure-related code
+ https://bugs.webkit.org/show_bug.cgi?id=102630
+
+ Reviewed by Simon Fraser.
+
+ - JSValue::description() now tells you if something is a structure, and if so,
+ what kind of structure it is.
+
+ - Jettisoning logic now tells you why things are being jettisoned.
+
+ - It's now possible to turn off GC-triggered jettisoning entirely.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::finalizeUnconditionally):
+ (JSC::CodeBlock::reoptimize):
+ (JSC::ProgramCodeBlock::jettison):
+ (JSC::EvalCodeBlock::jettison):
+ (JSC::FunctionCodeBlock::jettison):
+ * bytecode/CodeBlock.h:
+ (JSC::CodeBlock::shouldImmediatelyAssumeLivenessDuringScan):
+ * runtime/JSValue.cpp:
+ (JSC::JSValue::description):
+ * runtime/Options.h:
+ (JSC):
+
+2012-11-18 Filip Pizlo <fpizlo@apple.com>
+
+ DFG constant folding phase should say 'changed = true' whenever it changes the graph
+ https://bugs.webkit.org/show_bug.cgi?id=102550
+
+ Rubber stamped by Mark Hahnenberg.
+
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+
+2012-11-17 Elliott Sprehn <esprehn@chromium.org>
+
+ Expose JSObject removeDirect and PrivateName to WebCore
+ https://bugs.webkit.org/show_bug.cgi?id=102546
+
+ Reviewed by Geoffrey Garen.
+
+ Export removeDirect for use in WebCore so JSDependentRetained works.
+
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+
+2012-11-16 Filip Pizlo <fpizlo@apple.com>
+
+ Given a PutById or GetById with a proven structure, the DFG should be able to emit a PutByOffset or GetByOffset instead
+ https://bugs.webkit.org/show_bug.cgi?id=102327
+
+ Reviewed by Mark Hahnenberg.
+
+ If the profiler tells us that a GetById or PutById may be polymorphic but our
+ control flow analysis proves that it isn't, we should trust the control flow
+ analysis over the profiler. This arises in cases where GetById or PutById were
+ inlined: the inlined function may have been called from other places that led
+ to polymorphism, but in the current inlined context, there is no polymorphism.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dump):
+ * bytecode/GetByIdStatus.cpp:
+ (JSC::GetByIdStatus::computeFor):
+ (JSC):
+ * bytecode/GetByIdStatus.h:
+ (JSC::GetByIdStatus::GetByIdStatus):
+ (GetByIdStatus):
+ * bytecode/PutByIdStatus.cpp:
+ (JSC::PutByIdStatus::computeFor):
+ (JSC):
+ * bytecode/PutByIdStatus.h:
+ (JSC):
+ (JSC::PutByIdStatus::PutByIdStatus):
+ (PutByIdStatus):
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGAbstractValue.h:
+ (JSC::DFG::AbstractValue::bestProvenStructure):
+ (AbstractValue):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ (JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck):
+ (ConstantFoldingPhase):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::convertToGetByOffset):
+ (Node):
+ (JSC::DFG::Node::convertToPutByOffset):
+ (JSC::DFG::Node::hasStorageResult):
+ * runtime/JSGlobalObject.h:
+ (JSC::Structure::prototypeChain):
+ (JSC):
+ (JSC::Structure::isValid):
+ * runtime/Operations.h:
+ (JSC::isPrototypeChainNormalized):
+ (JSC):
+ * runtime/Structure.h:
+ (Structure):
+ (JSC::Structure::transitionDidInvolveSpecificValue):
+
+2012-11-16 Tony Chang <tony@chromium.org>
+
+ Remove ENABLE_CSS_HIERARCHIES since it's no longer in use
+ https://bugs.webkit.org/show_bug.cgi?id=102554
+
+ Reviewed by Andreas Kling.
+
+ As mentioned in https://bugs.webkit.org/show_bug.cgi?id=79939#c41 ,
+ we're going to revist this feature once additional vendor support is
+ achieved.
+
+ * Configurations/FeatureDefines.xcconfig:
+
+2012-11-16 Patrick Gansterer <paroga@webkit.org>
+
+ Build fix for WinCE after r133688.
+
+ Use numeric_limits<uint32_t>::max() instead of UINT32_MAX.
+
+ * runtime/CodeCache.h:
+ (JSC::CacheMap::CacheMap):
+
+2012-11-15 Filip Pizlo <fpizlo@apple.com>
+
+ ClassInfo.h should have correct indentation.
+
+ Rubber stamped by Mark Hahnenberg.
+
+ ClassInfo.h had some true creativity in its use of whitespace. Some things within
+ the namespace were indented four spaces and others where not. One #define had its
+ contents indented four spaces, while another didn't. I applied the following rule:
+
+ - Non-macro things in the namespace should not be indented (that's our current
+ accepted practice).
+
+ - Macros should never be indented but if they are multi-line then their subsequent
+ bodies should be indented four spaces. I believe that is consistent with what we
+ do elsewhere.
+
+ * runtime/ClassInfo.h:
+ (JSC):
+ (MethodTable):
+ (ClassInfo):
+ (JSC::ClassInfo::propHashTable):
+ (JSC::ClassInfo::isSubClassOf):
+ (JSC::ClassInfo::hasStaticProperties):
+
+2012-11-15 Filip Pizlo <fpizlo@apple.com>
+
+ DFG should copy propagate trivially no-op ConvertThis
+ https://bugs.webkit.org/show_bug.cgi?id=102445
+
+ Reviewed by Oliver Hunt.
+
+ Copy propagation is always a good thing, since it reveals must-alias relationships
+ to the CFA and CSE. This accomplishes copy propagation for ConvertThis by first
+ converting it to an Identity node (which is done by the constant folder since it
+ has access to CFA results) and then performing substitution of references to
+ Identity with references to Identity's child in the CSE.
+
+ I'm not aiming for a big speed-up here; I just think that this will be useful for
+ the work on https://bugs.webkit.org/show_bug.cgi?id=102327.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::performNodeCSE):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ * dfg/DFGNodeType.h:
+ (DFG):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+
+2012-11-15 Filip Pizlo <fpizlo@apple.com>
+
+ CallData.h should have correct indentation.
+
+ Rubber stamped by Mark Hahneberg.
+
+ * runtime/CallData.h:
+ (JSC):
+
+2012-11-15 Filip Pizlo <fpizlo@apple.com>
+
+ Remove methodCallDummy since it is not used anymore.
+
+ Rubber stamped by Mark Hahnenberg.
+
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::reset):
+ (JSC):
+ (JSC::JSGlobalObject::visitChildren):
+ * runtime/JSGlobalObject.h:
+ (JSGlobalObject):
+
+2012-11-14 Filip Pizlo <fpizlo@apple.com>
+
+ Structure should be able to easily tell if the prototype chain might intercept a store
+ https://bugs.webkit.org/show_bug.cgi?id=102326
+
+ Reviewed by Geoffrey Garen.
+
+ This improves our ability to reason about the correctness of the more optimized
+ prototype chain walk in JSObject::put(), while also making it straight forward to
+ check if the prototype chain will do strange things to a property store by just
+ looking at the structure.
+
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::put):
+ * runtime/Structure.cpp:
+ (JSC::Structure::prototypeChainMayInterceptStoreTo):
+ (JSC):
+ * runtime/Structure.h:
+ (Structure):
+
+2012-11-15 Thiago Marcos P. Santos <thiago.santos@intel.com>
+
+ [CMake] Do not regenerate LLIntAssembly.h on every incremental build
+ https://bugs.webkit.org/show_bug.cgi?id=102248
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Update LLIntAssembly.h's mtime after running asm.rb to make the build
+ system dependency tracking consistent.
+
+ * CMakeLists.txt:
+
+2012-11-15 Thiago Marcos P. Santos <thiago.santos@intel.com>
+
+ Fix compiler warnings about signed/unsigned comparison on i386
+ https://bugs.webkit.org/show_bug.cgi?id=102249
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Add casting to unsigned to shut up gcc warnings. Build was broken on
+ JSVALUE32_64 ports compiling with -Werror.
+
+ * llint/LLIntData.cpp:
+ (JSC::LLInt::Data::performAssertions):
+
+2012-11-14 Brent Fulgham <bfulgham@webkit.org>
+
+ [Windows, WinCairo] Unreviewed build fix.
+
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+ Missed one of the exports that was part of the WebKit2.def.
+
+2012-11-14 Brent Fulgham <bfulgham@webkit.org>
+
+ [Windows, WinCairo] Correct build failure.
+ https://bugs.webkit.org/show_bug.cgi?id=102302
+
+ WebCore symbols were mistakenly added to the JavaScriptCore
+ library definition file.
+
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Remove
+ WebCore symbols that were incorrectly added to the export file.
+
+2012-11-14 Mark Lam <mark.lam@apple.com>
+
+ Change JSEventListener::m_jsFunction to be a weak ref.
+ https://bugs.webkit.org/show_bug.cgi?id=101989.
+
+ Reviewed by Geoffrey Garen.
+
+ Added infrastructure for scanning weak ref slots.
+
+ * heap/SlotVisitor.cpp: Added #include "SlotVisitorInlines.h".
+ * heap/SlotVisitor.h:
+ (SlotVisitor): Added SlotVisitor::appendUnbarrieredWeak().
+ * heap/SlotVisitorInlines.h: Added #include "Weak.h".
+ (JSC::SlotVisitor::appendUnbarrieredWeak): Added.
+ * heap/Weak.h:
+ (JSC::operator==): Added operator==() for Weak.
+ * runtime/JSCell.h: Removed #include "SlotVisitorInlines.h".
+ * runtime/JSObject.h: Added #include "SlotVisitorInlines.h".
+
+2012-11-14 Filip Pizlo <fpizlo@apple.com>
+
+ Read-only properties created with putDirect() should tell the structure that there are read-only properties
+ https://bugs.webkit.org/show_bug.cgi?id=102292
+
+ Reviewed by Gavin Barraclough.
+
+ This mostly affects things like function.length.
+
+ * runtime/JSObject.h:
+ (JSC::JSObject::putDirectInternal):
+
+2012-11-13 Filip Pizlo <fpizlo@apple.com>
+
+ Don't access Node& after adding nodes to the graph.
+ https://bugs.webkit.org/show_bug.cgi?id=102005
+
+ Reviewed by Oliver Hunt.
+
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+
+2012-11-14 Valery Ignatyev <valery.ignatyev@ispras.ru>
+
+ Replace (typeof(x) != <"object", "undefined", ...>) with
+ !(typeof(x) == <"object",..>). Later is_object, is_<...> bytecode operation
+ will be used.
+
+ https://bugs.webkit.org/show_bug.cgi?id=98893
+
+ Reviewed by Filip Pizlo.
+
+ This eliminates expensive typeof implementation and
+ allows to use DFG optimizations, which doesn't support 'typeof'.
+
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::BinaryOpNode::emitBytecode):
+
+2012-11-14 Peter Gal <galpeter@inf.u-szeged.hu>
+
+ [Qt][ARM]REGRESSION(r133985): It broke the build
+ https://bugs.webkit.org/show_bug.cgi?id=101740
+
+ Reviewed by Csaba Osztrogonác.
+
+ Changed the emitGenericContiguousPutByVal to accept the additional IndexingType argument.
+ This information was passed as a template parameter.
+
+ * jit/JIT.h:
+ (JSC::JIT::emitInt32PutByVal):
+ (JSC::JIT::emitDoublePutByVal):
+ (JSC::JIT::emitContiguousPutByVal):
+ (JIT):
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emitGenericContiguousPutByVal):
+ * jit/JITPropertyAccess32_64.cpp:
+ (JSC::JIT::emitGenericContiguousPutByVal):
+
+2012-11-14 Peter Gal <galpeter@inf.u-szeged.hu>
+
+ Fix the MIPS build after r134332
+ https://bugs.webkit.org/show_bug.cgi?id=102227
+
+ Reviewed by Csaba Osztrogonác.
+
+ Added missing methods for the MacroAssemblerMIPS, based on the MacroAssemblerARMv7.
+
+ * assembler/MacroAssemblerMIPS.h:
+ (JSC::MacroAssemblerMIPS::canJumpReplacePatchableBranchPtrWithPatch):
+ (MacroAssemblerMIPS):
+ (JSC::MacroAssemblerMIPS::startOfPatchableBranchPtrWithPatch):
+ (JSC::MacroAssemblerMIPS::revertJumpReplacementToPatchableBranchPtrWithPatch):
+
+2012-11-14 Peter Gal <galpeter@inf.u-szeged.hu>
+
+ Fix the [-Wreturn-type] warning in JavaScriptCore/assembler/MacroAssemblerARM.h
+ https://bugs.webkit.org/show_bug.cgi?id=102206
+
+ Reviewed by Csaba Osztrogonác.
+
+ Add a return value for the function to suppress the warning.
+
+ * assembler/MacroAssemblerARM.h:
+ (JSC::MacroAssemblerARM::startOfPatchableBranchPtrWithPatch):
+
+2012-11-14 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r134599.
+ http://trac.webkit.org/changeset/134599
+ https://bugs.webkit.org/show_bug.cgi?id=102225
+
+ It broke the 32 bit EFL build (Requested by Ossy on #webkit).
+
+ * jit/JITPropertyAccess.cpp:
+ * jit/JITPropertyAccess32_64.cpp:
+ (JSC):
+ (JSC::JIT::emitGenericContiguousPutByVal):
+
+2012-11-14 Balazs Kilvady <kilvadyb@homejinni.com>
+
+ [Qt][ARM]REGRESSION(r133985): It broke the build
+ https://bugs.webkit.org/show_bug.cgi?id=101740
+
+ Reviewed by Csaba Osztrogonác.
+
+ Template function body moved to fix VALUE_PROFILER disabled case.
+
+ * jit/JITPropertyAccess.cpp:
+ (JSC):
+ (JSC::JIT::emitGenericContiguousPutByVal):
+ * jit/JITPropertyAccess32_64.cpp:
+
+2012-11-13 Filip Pizlo <fpizlo@apple.com>
+
+ DFG CreateThis should be able to statically account for the structure of the object it creates, if profiling indicates that this structure is always the same
+ https://bugs.webkit.org/show_bug.cgi?id=102017
+
+ Reviewed by Geoffrey Garen.
+
+ This adds a watchpoint in JSFunction on the cached inheritor ID. It also changes
+ NewObject to take a structure as an operand (previously it implicitly used the owning
+ global object's empty object structure). Any GetCallee where the callee is predictable
+ is turned into a CheckFunction + WeakJSConstant, and any CreateThis on a WeakJSConstant
+ where the inheritor ID watchpoint is still valid is turned into an InheritorIDWatchpoint
+ followed by a NewObject. NewObject already accounts for the structure it uses for object
+ creation in the CFA.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::checkFunctionElimination):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::dump):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasFunction):
+ (JSC::DFG::Node::function):
+ (JSC::DFG::Node::hasStructure):
+ * dfg/DFGNodeType.h:
+ (DFG):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::callOperation):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * runtime/Executable.h:
+ (JSC::JSFunction::JSFunction):
+ * runtime/JSBoundFunction.cpp:
+ (JSC):
+ * runtime/JSFunction.cpp:
+ (JSC::JSFunction::JSFunction):
+ (JSC::JSFunction::put):
+ (JSC::JSFunction::defineOwnProperty):
+ * runtime/JSFunction.h:
+ (JSC::JSFunction::tryGetKnownInheritorID):
+ (JSFunction):
+ (JSC::JSFunction::addInheritorIDWatchpoint):
+
+2012-11-13 Filip Pizlo <fpizlo@apple.com>
+
+ JSFunction and its descendants should be destructible
+ https://bugs.webkit.org/show_bug.cgi?id=102062
+
+ Reviewed by Mark Hahnenberg.
+
+ This will make it easy to place an InlineWatchpointSet inside JSFunction. In the
+ future, we could make JSFunction non-destructible again by making a version of
+ WatchpointSet that is entirely GC'd, but this seems like overkill for now.
+
+ This is performance-neutral.
+
+ * runtime/JSBoundFunction.cpp:
+ (JSC::JSBoundFunction::destroy):
+ (JSC):
+ * runtime/JSBoundFunction.h:
+ (JSBoundFunction):
+ * runtime/JSFunction.cpp:
+ (JSC):
+ (JSC::JSFunction::destroy):
+ * runtime/JSFunction.h:
+ (JSFunction):
+
+2012-11-13 Cosmin Truta <ctruta@rim.com>
+
+ Uninitialized fields in class JSLock
+ https://bugs.webkit.org/show_bug.cgi?id=101695
+
+ Reviewed by Mark Hahnenberg.
+
+ Initialize JSLock::m_ownerThread and JSLock::m_lockDropDepth.
+
+ * runtime/JSLock.cpp:
+ (JSC::JSLock::JSLock):
+
+2012-11-13 Peter Gal <galpeter@inf.u-szeged.hu>
+
+ Fix the ARM traditional build after r134332
+ https://bugs.webkit.org/show_bug.cgi?id=102044
+
+ Reviewed by Zoltan Herczeg.
+
+ Added missing methods for the MacroAssemblerARM, based on the MacroAssemblerARMv7.
+
+ * assembler/MacroAssemblerARM.h:
+ (JSC::MacroAssemblerARM::canJumpReplacePatchableBranchPtrWithPatch):
+ (MacroAssemblerARM):
+ (JSC::MacroAssemblerARM::startOfPatchableBranchPtrWithPatch):
+ (JSC::MacroAssemblerARM::revertJumpReplacementToPatchableBranchPtrWithPatch):
+
+2012-11-12 Filip Pizlo <fpizlo@apple.com>
+
+ op_get_callee should have value profiling
+ https://bugs.webkit.org/show_bug.cgi?id=102047
+
+ Reviewed by Sam Weinig.
+
+ This will allow us to detect if the callee is always the same, which is probably
+ the common case for a lot of constructors.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::CodeBlock):
+ * bytecode/Opcode.h:
+ (JSC):
+ (JSC::padOpcodeName):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::BytecodeGenerator):
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_get_callee):
+ * jit/JITOpcodes32_64.cpp:
+ (JSC::JIT::emit_op_get_callee):
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+
+2012-11-12 Filip Pizlo <fpizlo@apple.com>
+
+ The act of getting the callee during 'this' construction should be explicit in bytecode
+ https://bugs.webkit.org/show_bug.cgi?id=102016
+
+ Reviewed by Michael Saboff.
+
+ This is mostly a rollout of http://trac.webkit.org/changeset/116673, but also includes
+ changes to have create_this use the result of get_callee.
+
+ No performance or behavioral impact. This is just meant to allow us to profile
+ get_callee in the future.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dump):
+ * bytecode/Opcode.h:
+ (JSC):
+ (JSC::padOpcodeName):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::BytecodeGenerator):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.h:
+ (JSC::DFG::canCompileOpcode):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ * jit/JIT.h:
+ (JIT):
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_get_callee):
+ (JSC):
+ (JSC::JIT::emit_op_create_this):
+ * jit/JITOpcodes32_64.cpp:
+ (JSC::JIT::emit_op_get_callee):
+ (JSC):
+ (JSC::JIT::emit_op_create_this):
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+
+2012-11-12 Filip Pizlo <fpizlo@apple.com>
+
+ Unreviewed, fix ARMv7 build.
+
+ * assembler/MacroAssemblerARMv7.h:
+ (JSC::MacroAssemblerARMv7::startOfPatchableBranchPtrWithPatch):
+ (JSC::MacroAssemblerARMv7::revertJumpReplacementToPatchableBranchPtrWithPatch):
+
+2012-11-12 Filip Pizlo <fpizlo@apple.com>
+
+ Patching of jumps to stubs should use jump replacement rather than branch destination overwrite
+ https://bugs.webkit.org/show_bug.cgi?id=101909
+
+ Reviewed by Geoffrey Garen.
+
+ This saves a few instructions in inline cases, on those architectures where it is
+ easy to figure out where to put the jump replacement. Sub-1% speed-up across the
+ board.
+
+ * assembler/MacroAssemblerARMv7.h:
+ (MacroAssemblerARMv7):
+ (JSC::MacroAssemblerARMv7::canJumpReplacePatchableBranchPtrWithPatch):
+ (JSC::MacroAssemblerARMv7::startOfPatchableBranchPtrWithPatch):
+ (JSC::MacroAssemblerARMv7::revertJumpReplacementToPatchableBranchPtrWithPatch):
+ * assembler/MacroAssemblerX86.h:
+ (JSC::MacroAssemblerX86::canJumpReplacePatchableBranchPtrWithPatch):
+ (MacroAssemblerX86):
+ (JSC::MacroAssemblerX86::startOfPatchableBranchPtrWithPatch):
+ (JSC::MacroAssemblerX86::revertJumpReplacementToPatchableBranchPtrWithPatch):
+ * assembler/MacroAssemblerX86_64.h:
+ (JSC::MacroAssemblerX86_64::canJumpReplacePatchableBranchPtrWithPatch):
+ (MacroAssemblerX86_64):
+ (JSC::MacroAssemblerX86_64::startOfPatchableBranchPtrWithPatch):
+ (JSC::MacroAssemblerX86_64::revertJumpReplacementToPatchableBranchPtrWithPatch):
+ * assembler/RepatchBuffer.h:
+ (JSC::RepatchBuffer::startOfPatchableBranchPtrWithPatch):
+ (RepatchBuffer):
+ (JSC::RepatchBuffer::replaceWithJump):
+ (JSC::RepatchBuffer::revertJumpReplacementToPatchableBranchPtrWithPatch):
+ * assembler/X86Assembler.h:
+ (X86Assembler):
+ (JSC::X86Assembler::revertJumpTo_movq_i64r):
+ (JSC::X86Assembler::revertJumpTo_cmpl_im_force32):
+ (X86InstructionFormatter):
+ * bytecode/StructureStubInfo.h:
+ * dfg/DFGRepatch.cpp:
+ (JSC::DFG::replaceWithJump):
+ (DFG):
+ (JSC::DFG::tryCacheGetByID):
+ (JSC::DFG::tryBuildGetByIDList):
+ (JSC::DFG::tryBuildGetByIDProtoList):
+ (JSC::DFG::tryCachePutByID):
+ (JSC::DFG::dfgResetGetByID):
+ (JSC::DFG::dfgResetPutByID):
+
+2012-11-11 Filip Pizlo <fpizlo@apple.com>
+
+ DFG ArithMul overflow check elimination is too aggressive
+ https://bugs.webkit.org/show_bug.cgi?id=101871
+
+ Reviewed by Oliver Hunt.
+
+ The code was ignoring the fact that ((a * b) | 0) == (((a | 0) * (b | 0)) | 0)
+ only holds if a * b < 2^53. So, I changed it to only enable the optimization
+ when a < 2^22 and b is an int32 (and vice versa), using a super trivial peephole
+ analysis to prove the inequality. I considered writing an epic forward flow
+ formulation that tracks the ranges of integer values but then I thought better
+ of it.
+
+ This also rewires the ArithMul integer speculation logic. Previously, we would
+ assume that an ArithMul was only UsedAsNumber if it escaped, and separately we
+ would decide whether to speculate integer based on a proof of the <2^22
+ inequality. Now, we treat the double rounding behavior of ArithMul as if the
+ result was UsedAsNumber even if it did not escape. Then we try to prove that
+ double rounding cannot happen by attemping to prove that a < 2^22. This then
+ feeds back into the decision of whether or not to speculate integer (if we fail
+ to prove a < 2^22 then we're UsedAsNumber, and if we're also MayOverflow then
+ that forces double speculation).
+
+ No performance impact. It just fixes a bug.
+
+ * dfg/DFGGraph.h:
+ (JSC::DFG::Graph::mulShouldSpeculateInteger):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (PredictionPropagationPhase):
+ (JSC::DFG::PredictionPropagationPhase::isWithinPowerOfTwoForConstant):
+ (JSC::DFG::PredictionPropagationPhase::isWithinPowerOfTwoNonRecursive):
+ (JSC::DFG::PredictionPropagationPhase::isWithinPowerOfTwo):
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+
+2012-11-11 Filip Pizlo <fpizlo@apple.com>
+
+ DFG should not emit function checks if we've already proved that the operand is that exact function
+ https://bugs.webkit.org/show_bug.cgi?id=101885
+
+ Reviewed by Oliver Hunt.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGAbstractValue.h:
+ (JSC::DFG::AbstractValue::filterByValue):
+ (AbstractValue):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+
+2012-11-12 Kentaro Hara <haraken@chromium.org>
+
+ [V8][JSC] ScriptProfileNode::callUID needs not to be [Custom]
+ https://bugs.webkit.org/show_bug.cgi?id=101892
+
+ Reviewed by Adam Barth.
+
+ Added callUID(), which enables us to kill custom bindings for ScriptProfileNode::callUID.
+
+ * profiler/ProfileNode.h:
+ (JSC::ProfileNode::callUID):
+
+2012-11-12 Carlos Garcia Campos <cgarcia@igalia.com>
+
+ Unreviewed. Fix make distcheck.
+
+ * GNUmakefile.list.am: Add missing header.
+
+2012-11-11 Michael Pruett <michael@68k.org>
+
+ Fix assertion failure in JSObject::tryGetIndexQuickly()
+ https://bugs.webkit.org/show_bug.cgi?id=101869
+
+ Reviewed by Filip Pizlo.
+
+ Currently JSObject::tryGetIndexQuickly() triggers an assertion
+ failure when the object has an undecided indexing type. This
+ case should be treated the same as a blank indexing type.
+
+ * runtime/JSObject.h:
+ (JSC::JSObject::tryGetIndexQuickly):
+
+2012-11-11 Filip Pizlo <fpizlo@apple.com>
+
+ DFG register allocation should be greedy rather than round-robin
+ https://bugs.webkit.org/show_bug.cgi?id=101870
+
+ Reviewed by Geoffrey Garen.
+
+ This simplifies the code, reduces some code duplication, and shows some slight
+ performance improvements in a few places, likely due to the fact that lower-numered
+ registers also typically have smaller encodings.
+
+ * dfg/DFGRegisterBank.h:
+ (JSC::DFG::RegisterBank::RegisterBank):
+ (JSC::DFG::RegisterBank::tryAllocate):
+ (JSC::DFG::RegisterBank::allocate):
+ (JSC::DFG::RegisterBank::allocateInternal):
+ (RegisterBank):
+
+2012-11-11 Kenichi Ishibashi <bashi@chromium.org>
+
+ WTFString::utf8() should have a mode of conversion to use replacement character
+ https://bugs.webkit.org/show_bug.cgi?id=101678
+
+ Reviewed by Alexey Proskuryakov.
+
+ Follow the change on String::utf8()
+
+ * runtime/JSGlobalObjectFunctions.cpp:
+ (JSC::encode): Pass String::StrictConversion instead of true to String::utf8().
+
+2012-11-10 Filip Pizlo <fpizlo@apple.com>
+
+ DFG should optimize out the NaN check on loads from double arrays if the array prototype chain is having a great time
+ https://bugs.webkit.org/show_bug.cgi?id=101718
+
+ Reviewed by Geoffrey Garen.
+
+ If we're reading from a JSArray in double mode, where the array's structure is
+ primordial (all aspects of the structure are unchanged except for indexing type),
+ and the result of the load is used in arithmetic that is known to not distinguish
+ between NaN and undefined, then we should not emit a NaN check. Looks like a 5%
+ win on navier-stokes.
+
+ Also fixed an OpInfo initialization goof for String ops that was revealed by this
+ change.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGArrayMode.cpp:
+ (JSC::DFG::arraySpeculationToString):
+ * dfg/DFGArrayMode.h:
+ (JSC::DFG::ArrayMode::isSaneChain):
+ (ArrayMode):
+ (JSC::DFG::ArrayMode::isInBounds):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleIntrinsic):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNodeFlags.cpp:
+ (JSC::DFG::nodeFlagsAsString):
+ * dfg/DFGNodeFlags.h:
+ (DFG):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::arrayPrototypeChainIsSane):
+ (JSC):
+ * runtime/JSGlobalObject.h:
+ (JSGlobalObject):
+
+2012-11-10 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 Geoffrey Garen.
+
+ This is the second attempt at this patch, which fixes the !"" case.
+
+ 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-10 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r133971.
+ http://trac.webkit.org/changeset/133971
+ https://bugs.webkit.org/show_bug.cgi?id=101839
+
+ Causes WebProcess to hang at 100% on www.apple.com (Requested
+ by kling on #webkit).
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::endBasicBlock):
+ (JSC::DFG::AbstractState::execute):
+ (JSC::DFG::AbstractState::mergeToSuccessors):
+ * dfg/DFGAbstractState.h:
+ (JSC::DFG::AbstractState::branchDirectionToString):
+ (AbstractState):
+ * dfg/DFGBasicBlock.h:
+ (JSC::DFG::BasicBlock::BasicBlock):
+ (BasicBlock):
+ * dfg/DFGBranchDirection.h: Removed.
+ * dfg/DFGCFGSimplificationPhase.cpp:
+ (JSC::DFG::CFGSimplificationPhase::run):
+ (JSC::DFG::CFGSimplificationPhase::mergeBlocks):
+
+2012-11-09 Filip Pizlo <fpizlo@apple.com>
+
+ If the DFG ArrayMode says that an access is on an OriginalArray, then the checks should always enforce this
+ https://bugs.webkit.org/show_bug.cgi?id=101720
+
+ Reviewed by Mark Hahnenberg.
+
+ Previously, "original" arrays was just a hint that we could find the structure
+ of the array if we needed to even if the array profile didn't have it due to
+ polymorphism. Now, "original" arrays are a property that is actually checked:
+ if an array access has ArrayMode::arrayClass() == Array::OriginalArray, then we
+ can be sure that the code performing the access is dealing with not just a
+ JSArray, but a JSArray that has no named properties, no indexed accessors, and
+ the ArrayPrototype as its prototype. This will be useful for optimizations that
+ are being done as part of https://bugs.webkit.org/show_bug.cgi?id=101720.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGArrayMode.cpp:
+ (JSC::DFG::ArrayMode::originalArrayStructure):
+ (DFG):
+ (JSC::DFG::ArrayMode::alreadyChecked):
+ * dfg/DFGArrayMode.h:
+ (JSC):
+ (DFG):
+ (JSC::DFG::ArrayMode::withProfile):
+ (ArrayMode):
+ (JSC::DFG::ArrayMode::benefitsFromOriginalArray):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::checkArray):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode):
+ (JSC::DFG::SpeculativeJIT::checkArray):
+ (JSC::DFG::SpeculativeJIT::compileGetByValOnString):
+ (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray):
+ (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray):
+ (JSC::DFG::SpeculativeJIT::compilePutByValForFloatTypedArray):
+ (JSC::DFG::SpeculativeJIT::compileGetByValOnArguments):
+ (JSC::DFG::SpeculativeJIT::compileGetArgumentsLength):
+
+2012-11-09 Filip Pizlo <fpizlo@apple.com>
+
+ Fix indentation of BooleanPrototype.h
+
+ Rubber stamped by Mark Hahnenberg.
+
+ * runtime/BooleanPrototype.h:
+
+2012-11-09 Filip Pizlo <fpizlo@apple.com>
+
+ Fix indentation of BooleanObject.h
+
+ Rubber stamped by Mark Hahnenberg.
+
+ * runtime/BooleanObject.h:
+
+2012-11-09 Filip Pizlo <fpizlo@apple.com>
+
+ Fix indentation of BooleanConstructor.h
+
+ Rubber stamped by Mark Hahnenberg.
+
+ * runtime/BooleanConstructor.h:
+
+2012-11-09 Filip Pizlo <fpizlo@apple.com>
+
+ Fix indentation of BatchedTransitionOptimizer.h
+
+ Rubber stamped by Mark Hahnenberg.
+
+ * runtime/BatchedTransitionOptimizer.h:
+
+2012-11-09 Oliver Hunt <oliver@apple.com>
+
+ So Thingy probably isn't the best name for a class, so
+ renamed to CacheMap.
+
+ RS=Geoff
+
+ * runtime/CodeCache.h:
+ (JSC::CacheMap::CacheMap):
+
+2012-11-09 Filip Pizlo <fpizlo@apple.com>
+
+ ArrayPrototype should start out with a blank indexing type
+ https://bugs.webkit.org/show_bug.cgi?id=101719
+
+ Reviewed by Mark Hahnenberg.
+
+ This allows us to track if the array prototype ever ends up with indexed
+ properties.
+
+ * runtime/ArrayPrototype.cpp:
+ (JSC::ArrayPrototype::create):
+ (JSC::ArrayPrototype::ArrayPrototype):
+ * runtime/ArrayPrototype.h:
+ (ArrayPrototype):
+ (JSC::ArrayPrototype::createStructure):
+
+2012-11-08 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ MarkStackArray should use the BlockAllocator instead of the MarkStackSegmentAllocator
+ https://bugs.webkit.org/show_bug.cgi?id=101642
+
+ Reviewed by Filip Pizlo.
+
+ MarkStackSegmentAllocator is like a miniature version of the BlockAllocator. Now that the BlockAllocator has support
+ for a variety of block sizes, we should get rid of the MarkStackSegmentAllocator in favor of the BlockAllocator.
+
+ * heap/BlockAllocator.h: Add new specializations of regionSetFor for the new MarkStackSegments.
+ (JSC):
+ (JSC::MarkStackSegment):
+ * heap/GCThreadSharedData.cpp:
+ (JSC::GCThreadSharedData::GCThreadSharedData):
+ (JSC::GCThreadSharedData::reset):
+ * heap/GCThreadSharedData.h:
+ (GCThreadSharedData):
+ * heap/MarkStack.cpp:
+ (JSC::MarkStackArray::MarkStackArray): We now have a doubly linked list of MarkStackSegments, so we need to refactor
+ all the places that used the old custom tail/previous logic.
+ (JSC::MarkStackArray::~MarkStackArray):
+ (JSC::MarkStackArray::expand):
+ (JSC::MarkStackArray::refill):
+ (JSC::MarkStackArray::donateSomeCellsTo): Refactor to use the new linked list.
+ (JSC::MarkStackArray::stealSomeCellsFrom): Ditto.
+ * heap/MarkStack.h:
+ (JSC):
+ (MarkStackSegment):
+ (JSC::MarkStackSegment::MarkStackSegment):
+ (JSC::MarkStackSegment::sizeFromCapacity):
+ (MarkStackArray):
+ * heap/MarkStackInlines.h:
+ (JSC::MarkStackSegment::create):
+ (JSC):
+ (JSC::MarkStackArray::postIncTop):
+ (JSC::MarkStackArray::preDecTop):
+ (JSC::MarkStackArray::setTopForFullSegment):
+ (JSC::MarkStackArray::setTopForEmptySegment):
+ (JSC::MarkStackArray::top):
+ (JSC::MarkStackArray::validatePrevious):
+ (JSC::MarkStackArray::append):
+ (JSC::MarkStackArray::removeLast):
+ (JSC::MarkStackArray::isEmpty):
+ (JSC::MarkStackArray::size):
+ * heap/SlotVisitor.cpp:
+ (JSC::SlotVisitor::SlotVisitor):
+
+2012-11-09 Gabor Ballabas <gaborb@inf.u-szeged.hu>
+
+ [Qt] r133953 broke the ARM_TRADITIONAL build
+ https://bugs.webkit.org/show_bug.cgi?id=101706
+
+ Reviewed by Csaba Osztrogonác.
+
+ Fix for both hardfp and softfp.
+
+ * dfg/DFGCCallHelpers.h:
+ (CCallHelpers):
+ (JSC::DFG::CCallHelpers::setupArgumentsWithExecState):
+
+2012-11-09 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r134051.
+ http://trac.webkit.org/changeset/134051
+ https://bugs.webkit.org/show_bug.cgi?id=101757
+
+ It didn't fix the build (Requested by Ossy on #webkit).
+
+ * dfg/DFGCCallHelpers.h:
+ (JSC::DFG::CCallHelpers::setupArgumentsWithExecState):
+
+2012-11-09 Gabor Ballabas <gaborb@inf.u-szeged.hu>
+
+ [Qt] r133953 broke the ARM_TRADITIONAL build
+ https://bugs.webkit.org/show_bug.cgi?id=101706
+
+ Reviewed by Csaba Osztrogonác.
+
+ Fix the ARM_TRADITIONAL build after r133953
+
+ * dfg/DFGCCallHelpers.h:
+ (JSC::DFG::CCallHelpers::setupArgumentsWithExecState):
+ (CCallHelpers):
+
2012-11-09 Csaba Osztrogonác <ossy@webkit.org>
[Qt] Fix the LLINT build from ARMv7 platform
@@ -10,6 +1576,650 @@
* 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
diff --git a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig
index a4f8ca0c0..0e1b15340 100644
--- a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig
+++ b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig
@@ -42,7 +42,6 @@ ENABLE_CSS_COMPOSITING = ENABLE_CSS_COMPOSITING;
ENABLE_CSS_DEVICE_ADAPTATION = ;
ENABLE_CSS_EXCLUSIONS = ENABLE_CSS_EXCLUSIONS;
ENABLE_CSS_FILTERS = ENABLE_CSS_FILTERS;
-ENABLE_CSS_HIERARCHIES = ;
ENABLE_CSS_IMAGE_ORIENTATION = ;
ENABLE_CSS_IMAGE_RESOLUTION = ;
ENABLE_CSS_REGIONS = ENABLE_CSS_REGIONS;
@@ -129,6 +128,7 @@ ENABLE_PDFKIT_PLUGIN_macosx_1070 = ;
ENABLE_PDFKIT_PLUGIN_macosx_1080 = ;
ENABLE_PDFKIT_PLUGIN_macosx_1090 = ENABLE_PDFKIT_PLUGIN;
ENABLE_PROGRESS_ELEMENT = ENABLE_PROGRESS_ELEMENT;
+ENABLE_PROXIMITY_EVENTS = ;
ENABLE_QUOTA = ;
ENABLE_REQUEST_ANIMATION_FRAME = ENABLE_REQUEST_ANIMATION_FRAME;
ENABLE_RESOLUTION_MEDIA_QUERY = ;
@@ -157,4 +157,4 @@ ENABLE_WORKERS = ENABLE_WORKERS;
ENABLE_XHR_TIMEOUT = ENABLE_XHR_TIMEOUT;
ENABLE_XSLT = ENABLE_XSLT;
-FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSP_NEXT) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_DEVICE_ADAPTATION) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_HIERARCHIES) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_STICKY_POSITION) $(ENABLE_CSS_VARIABLES) $(ENABLE_CSS3_CONDITIONAL_RULES) $(ENABLE_CSS3_TEXT) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIALOG_ELEMENT) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_DRAGGABLE_REGION) $(ENABLE_ENCRYPTED_MEDIA) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LEGACY_VENDOR_PREFIXES) $(ENABLE_LEGACY_WEB_AUDIO) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NAVIGATOR_CONTENT_UTILS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PDFKIT_PLUGIN) $(ENABLE_PROGRESS_ELEMENT) $(ENABLE_QUOTA) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_RESOLUTION_MEDIA_QUERY) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SUBPIXEL_LAYOUT) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_AUTOSIZING) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_USERSELECT_ALL) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WORKERS) $(ENABLE_XHR_TIMEOUT) $(ENABLE_XSLT);
+FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSP_NEXT) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_DEVICE_ADAPTATION) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_STICKY_POSITION) $(ENABLE_CSS_VARIABLES) $(ENABLE_CSS3_CONDITIONAL_RULES) $(ENABLE_CSS3_TEXT) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIALOG_ELEMENT) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_DRAGGABLE_REGION) $(ENABLE_ENCRYPTED_MEDIA) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LEGACY_VENDOR_PREFIXES) $(ENABLE_LEGACY_WEB_AUDIO) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NAVIGATOR_CONTENT_UTILS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PDFKIT_PLUGIN) $(ENABLE_PROGRESS_ELEMENT) $(ENABLE_PROXIMITY_EVENTS) $(ENABLE_QUOTA) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_RESOLUTION_MEDIA_QUERY) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SUBPIXEL_LAYOUT) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_AUTOSIZING) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_USERSELECT_ALL) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WORKERS) $(ENABLE_XHR_TIMEOUT) $(ENABLE_XSLT);
diff --git a/Source/JavaScriptCore/Configurations/Version.xcconfig b/Source/JavaScriptCore/Configurations/Version.xcconfig
index f2d37774e..4f8baa4f2 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 = 19;
+MINOR_VERSION = 20;
TINY_VERSION = 0;
FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION);
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index d68a22b9f..d7afaf18a 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 \
@@ -162,6 +164,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/dfg/DFGAssemblyHelpers.cpp \
Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h \
Source/JavaScriptCore/dfg/DFGBasicBlock.h \
+ Source/JavaScriptCore/dfg/DFGBranchDirection.h \
Source/JavaScriptCore/dfg/DFGByteCodeCache.h \
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp \
Source/JavaScriptCore/dfg/DFGByteCodeParser.h \
@@ -249,14 +252,15 @@ javascriptcore_sources += \
Source/JavaScriptCore/dfg/DFGVariableAccessData.h \
Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp \
Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.h \
+ Source/JavaScriptCore/disassembler/Disassembler.cpp \
Source/JavaScriptCore/disassembler/Disassembler.h \
Source/JavaScriptCore/heap/CopiedAllocator.h \
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 +278,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 +301,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 \
@@ -381,6 +385,8 @@ javascriptcore_sources += \
Source/JavaScriptCore/interpreter/VMInspector.h \
Source/JavaScriptCore/JavaScriptCorePrefix.h \
Source/JavaScriptCore/jit/CompactJITCodeMap.h \
+ Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp \
+ Source/JavaScriptCore/jit/ClosureCallStubRoutine.h \
Source/JavaScriptCore/jit/ExecutableAllocator.cpp \
Source/JavaScriptCore/jit/ExecutableAllocator.h \
Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp \
@@ -393,12 +399,14 @@ javascriptcore_sources += \
Source/JavaScriptCore/jit/JITCall.cpp \
Source/JavaScriptCore/jit/JITCode.h \
Source/JavaScriptCore/jit/JITCompilationEffort.h \
+ Source/JavaScriptCore/jit/JITDisassembler.cpp \
+ Source/JavaScriptCore/jit/JITDisassembler.h \
Source/JavaScriptCore/jit/JITDriver.h \
Source/JavaScriptCore/jit/JIT.cpp \
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 +489,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 +537,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 +598,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.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
index b23100547..94b8c2371 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
@@ -146,7 +148,7 @@ EXPORTS
?currentTime@WTF@@YANXZ
?customHasInstance@JSCell@JSC@@KA_NPAVJSObject@2@PAVExecState@2@VJSValue@2@@Z
?data@CString@WTF@@QBEPBDXZ
- ?dataLog@WTF@@YAXPBDZZ
+ ?dataLogF@WTF@@YAXPBDZZ
?dateToDaysFrom1970@WTF@@YANHHH@Z
?dayInMonthFromDayInYear@WTF@@YAHH_N@Z
?dayInYear@WTF@@YAHNH@Z
@@ -312,6 +314,7 @@ EXPORTS
?releaseDecommitted@OSAllocator@WTF@@SAXPAXI@Z
?releaseExecutableMemory@JSGlobalData@JSC@@QAEXXZ
?removeBlock@MarkedAllocator@JSC@@QAEXPAVMarkedBlock@2@@Z
+ ?removeDirect@JSObject@JSC@@QAE_NAAVJSGlobalData@2@VPropertyName@2@@Z
?reportAbandonedObjectGraph@Heap@JSC@@QAEXXZ
?reportExtraMemoryCostSlowCase@Heap@JSC@@AAEXI@Z
?reportSuccess@HeapStatistics@JSC@@SAXXZ
@@ -333,6 +336,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 +406,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..d26a3b645 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>
@@ -1922,6 +1930,14 @@
Name="jit"
>
<File
+ RelativePath="..\..\jit\ClosureCallStubRoutine.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\jit\ClosureCallStubRoutine.h"
+ >
+ </File>
+ <File
RelativePath="..\..\jit\ExecutableAllocator.cpp"
>
</File>
@@ -1970,6 +1986,14 @@
>
</File>
<File
+ RelativePath="..\..\jit\JITDisassembler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\jit\JITDisassembler.h"
+ >
+ </File>
+ <File
RelativePath="..\..\jit\JITExceptions.cpp"
>
</File>
@@ -1978,7 +2002,7 @@
>
</File>
<File
- RelativePath="..\..\jit\JITInlineMethods.h"
+ RelativePath="..\..\jit\JITInlines.h"
>
</File>
<File
@@ -2118,6 +2142,10 @@
Name="disassembler"
>
<File
+ RelativePath="..\..\disassembler\Disassembler.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\disassembler\Disassembler.h"
>
</File>
@@ -2354,7 +2382,7 @@
>
</File>
<File
- RelativePath="..\..\heap\CopiedSpaceInlineMethods.h"
+ RelativePath="..\..\heap\CopiedSpaceInlines.h"
>
</File>
<File
@@ -2366,7 +2394,7 @@
>
</File>
<File
- RelativePath="..\..\heap\CopyVisitorInlineMethods.h"
+ RelativePath="..\..\heap\CopyVisitorInlines.h"
>
</File>
<File
@@ -2554,7 +2582,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..bda9b27ff 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -147,6 +147,8 @@
0F63948515E4811B006A597C /* DFGArrayMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63948215E48114006A597C /* DFGArrayMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F66E16B14DF3F1600B7B2E4 /* DFGAdjacencyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F66E16C14DF3F1600B7B2E4 /* DFGEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F73D7AE165A142D00ACAB71 /* ClosureCallStubRoutine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F73D7AB165A142A00ACAB71 /* ClosureCallStubRoutine.cpp */; };
+ 0F73D7AF165A143000ACAB71 /* ClosureCallStubRoutine.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F73D7AC165A142A00ACAB71 /* ClosureCallStubRoutine.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F766D2815A8CC1E008F363E /* JITStubRoutine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D2615A8CC1B008F363E /* JITStubRoutine.cpp */; };
0F766D2B15A8CC38008F363E /* JITStubRoutineSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D2915A8CC34008F363E /* JITStubRoutineSet.cpp */; };
0F766D2C15A8CC3A008F363E /* JITStubRoutineSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F766D2A15A8CC34008F363E /* JITStubRoutineSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -165,6 +167,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, ); }; };
+ 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, ); }; };
+ 0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8364B5164B0C0E0053329A /* DFGBranchDirection.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 */; };
@@ -180,12 +185,15 @@
0F9332A414CA7DD90085F3C6 /* PutByIdStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F9332A514CA7DDD0085F3C6 /* StructureSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329B14CA7DC10085F3C6 /* StructureSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F9D3370165DBB90005AD387 /* Disassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9D336E165DBB8D005AD387 /* Disassembler.cpp */; };
0F9FC8C314E1B5FE00D52AE0 /* PolymorphicPutByIdList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9FC8BF14E1B5FB00D52AE0 /* PolymorphicPutByIdList.cpp */; };
0F9FC8C414E1B60000D52AE0 /* PolymorphicPutByIdList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9FC8C014E1B5FB00D52AE0 /* PolymorphicPutByIdList.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F9FC8C514E1B60400D52AE0 /* PutKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9FC8C114E1B5FB00D52AE0 /* PutKind.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FA581BA150E952C00B9A2D9 /* DFGNodeFlags.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FA581B7150E952A00B9A2D9 /* DFGNodeFlags.cpp */; };
0FA581BB150E953000B9A2D9 /* DFGNodeFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA581B8150E952A00B9A2D9 /* DFGNodeFlags.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FA581BC150E953000B9A2D9 /* DFGNodeType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0FAF7EFD165BA91B000C8455 /* JITDisassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FAF7EFA165BA919000C8455 /* JITDisassembler.cpp */; };
+ 0FAF7EFE165BA91F000C8455 /* JITDisassembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FAF7EFB165BA919000C8455 /* JITDisassembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FB5467714F59B5C002C2989 /* LazyOperandValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5467614F59AD1002C2989 /* LazyOperandValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FB5467914F5C46B002C2989 /* LazyOperandValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */; };
0FB5467B14F5C7E1002C2989 /* MethodOfGettingAValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -193,9 +201,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 +458,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 +494,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 +719,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 +736,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 */; };
@@ -935,6 +943,8 @@
0F63948215E48114006A597C /* DFGArrayMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArrayMode.h; path = dfg/DFGArrayMode.h; sourceTree = "<group>"; };
0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAdjacencyList.h; path = dfg/DFGAdjacencyList.h; sourceTree = "<group>"; };
0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGEdge.h; path = dfg/DFGEdge.h; sourceTree = "<group>"; };
+ 0F73D7AB165A142A00ACAB71 /* ClosureCallStubRoutine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClosureCallStubRoutine.cpp; sourceTree = "<group>"; };
+ 0F73D7AC165A142A00ACAB71 /* ClosureCallStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClosureCallStubRoutine.h; sourceTree = "<group>"; };
0F766D1C15A5028D008F363E /* JITStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubRoutine.h; sourceTree = "<group>"; };
0F766D2615A8CC1B008F363E /* JITStubRoutine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITStubRoutine.cpp; sourceTree = "<group>"; };
0F766D2915A8CC34008F363E /* JITStubRoutineSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITStubRoutineSet.cpp; sourceTree = "<group>"; };
@@ -951,6 +961,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>"; };
+ 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>"; };
+ 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBranchDirection.h; path = dfg/DFGBranchDirection.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>"; };
@@ -966,12 +979,15 @@
0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByIdStatus.h; sourceTree = "<group>"; };
0F93329B14CA7DC10085F3C6 /* StructureSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureSet.h; sourceTree = "<group>"; };
0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValueProfile.h; sourceTree = "<group>"; };
+ 0F9D336E165DBB8D005AD387 /* Disassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Disassembler.cpp; path = disassembler/Disassembler.cpp; sourceTree = "<group>"; };
0F9FC8BF14E1B5FB00D52AE0 /* PolymorphicPutByIdList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PolymorphicPutByIdList.cpp; sourceTree = "<group>"; };
0F9FC8C014E1B5FB00D52AE0 /* PolymorphicPutByIdList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolymorphicPutByIdList.h; sourceTree = "<group>"; };
0F9FC8C114E1B5FB00D52AE0 /* PutKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutKind.h; sourceTree = "<group>"; };
0FA581B7150E952A00B9A2D9 /* DFGNodeFlags.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGNodeFlags.cpp; path = dfg/DFGNodeFlags.cpp; sourceTree = "<group>"; };
0FA581B8150E952A00B9A2D9 /* DFGNodeFlags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGNodeFlags.h; path = dfg/DFGNodeFlags.h; sourceTree = "<group>"; };
0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGNodeType.h; path = dfg/DFGNodeType.h; sourceTree = "<group>"; };
+ 0FAF7EFA165BA919000C8455 /* JITDisassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITDisassembler.cpp; sourceTree = "<group>"; };
+ 0FAF7EFB165BA919000C8455 /* JITDisassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITDisassembler.h; sourceTree = "<group>"; };
0FB5467614F59AD1002C2989 /* LazyOperandValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyOperandValueProfile.h; sourceTree = "<group>"; };
0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LazyOperandValueProfile.cpp; sourceTree = "<group>"; };
0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MethodOfGettingAValueProfile.h; sourceTree = "<group>"; };
@@ -979,9 +995,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 +1022,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 +1242,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 +1284,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 +1517,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 +1532,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>"; };
@@ -1735,6 +1751,7 @@
isa = PBXGroup;
children = (
0FF42733158EBD64004CB9FF /* udis86 */,
+ 0F9D336E165DBB8D005AD387 /* Disassembler.cpp */,
0FF4272F158EBD44004CB9FF /* Disassembler.h */,
0FF42730158EBD44004CB9FF /* UDis86Disassembler.cpp */,
);
@@ -1797,6 +1814,8 @@
1429D92C0ED22D7000B89619 /* jit */ = {
isa = PBXGroup;
children = (
+ 0F73D7AB165A142A00ACAB71 /* ClosureCallStubRoutine.cpp */,
+ 0F73D7AC165A142A00ACAB71 /* ClosureCallStubRoutine.h */,
0FD82E37141AB14200179C94 /* CompactJITCodeMap.h */,
A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */,
A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */,
@@ -1813,10 +1832,12 @@
146FE51111A710430087AE66 /* JITCall32_64.cpp */,
86CCEFDD0F413F8900FD7F9E /* JITCode.h */,
0F0776BD14FF002800102332 /* JITCompilationEffort.h */,
+ 0FAF7EFA165BA919000C8455 /* JITDisassembler.cpp */,
+ 0FAF7EFB165BA919000C8455 /* JITDisassembler.h */,
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 +1863,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 +1871,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 +1885,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 +1917,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 +2121,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 +2167,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 +2224,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 +2383,7 @@
0FC0976B1468AB4A00CF2442 /* DFGAssemblyHelpers.cpp */,
0FC0976C1468AB4A00CF2442 /* DFGAssemblyHelpers.h */,
0F620170143FCD2F0068B77C /* DFGBasicBlock.h */,
+ 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */,
0F5F08CC146BE602000472A9 /* DFGByteCodeCache.h */,
86EC9DB41328DF82002B2AD7 /* DFGByteCodeParser.cpp */,
86EC9DB51328DF82002B2AD7 /* DFGByteCodeParser.h */,
@@ -2515,6 +2537,8 @@
969A078F0ED1D3AE00F1F681 /* bytecode */ = {
isa = PBXGroup;
children = (
+ 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */,
+ 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */,
0F63945115D07051006A597C /* ArrayProfile.cpp */,
0F63945215D07051006A597C /* ArrayProfile.h */,
0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */,
@@ -2616,14 +2640,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 +2660,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 +2742,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 +2784,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 +3018,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,9 +3032,13 @@
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 */,
+ 0FAF7EFE165BA91F000C8455 /* JITDisassembler.h in Headers */,
+ 0F73D7AF165A143000ACAB71 /* ClosureCallStubRoutine.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3587,8 +3615,12 @@
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 */,
+ 0FAF7EFD165BA91B000C8455 /* JITDisassembler.cpp in Sources */,
+ 0F73D7AE165A142D00ACAB71 /* ClosureCallStubRoutine.cpp in Sources */,
+ 0F9D3370165DBB90005AD387 /* Disassembler.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index b0fcc16e7..e15b21dae 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 \
@@ -139,10 +140,12 @@ SOURCES += \
dfg/DFGVariableEventStream.cpp \
dfg/DFGValidate.cpp \
dfg/DFGVirtualRegisterAllocationPhase.cpp \
+ disassembler/Disassembler.cpp \
interpreter/AbstractPC.cpp \
interpreter/CallFrame.cpp \
interpreter/Interpreter.cpp \
interpreter/JSStack.cpp \
+ jit/ClosureCallStubRoutine.cpp \
jit/ExecutableAllocatorFixedVMPool.cpp \
jit/ExecutableAllocator.cpp \
jit/HostCallReturnValue.cpp \
@@ -152,6 +155,7 @@ SOURCES += \
jit/JITCall.cpp \
jit/JITCall32_64.cpp \
jit/JIT.cpp \
+ jit/JITDisassembler.cpp \
jit/JITExceptions.cpp \
jit/JITOpcodes.cpp \
jit/JITOpcodes32_64.cpp \
diff --git a/Source/JavaScriptCore/assembler/ARMv7Assembler.h b/Source/JavaScriptCore/assembler/ARMv7Assembler.h
index e9b9fcc50..b93ec6e63 100644
--- a/Source/JavaScriptCore/assembler/ARMv7Assembler.h
+++ b/Source/JavaScriptCore/assembler/ARMv7Assembler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2010 University of Szeged
*
* Redistribution and use in source and binary forms, with or without
@@ -507,7 +507,7 @@ public:
private:
// ARMv7, Appx-A.6.3
- bool BadReg(RegisterID reg)
+ static bool BadReg(RegisterID reg)
{
return (reg == ARMRegisters::sp) || (reg == ARMRegisters::pc);
}
@@ -1261,6 +1261,18 @@ public:
m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm);
}
+
+ static void revertJumpTo_movT3(void* instructionStart, RegisterID rd, ARMThumbImmediate imm)
+ {
+ ASSERT(imm.isValid());
+ ASSERT(!imm.isEncodedImm());
+ ASSERT(!BadReg(rd));
+
+ uint16_t* address = static_cast<uint16_t*>(instructionStart);
+ address[0] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, imm);
+ address[1] = twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, imm);
+ cacheFlush(address, sizeof(uint16_t) * 2);
+ }
ALWAYS_INLINE void mov(RegisterID rd, ARMThumbImmediate imm)
{
@@ -1928,7 +1940,6 @@ public:
return LinkConditionalBX;
const int paddingSize = JUMP_ENUM_SIZE(jumpType);
- bool mayTriggerErrata = false;
if (jumpType == JumpCondition) {
// 2-byte conditional T1
@@ -1937,17 +1948,13 @@ public:
return LinkJumpT1;
// 4-byte conditional T3
const uint16_t* jumpT3Location = reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT3)));
- if (canBeJumpT3(jumpT3Location, to, mayTriggerErrata)) {
- if (!mayTriggerErrata)
- return LinkJumpT3;
- }
+ if (canBeJumpT3(jumpT3Location, to))
+ return LinkJumpT3;
// 4-byte conditional T4 with IT
const uint16_t* conditionalJumpT4Location =
reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkConditionalJumpT4)));
- if (canBeJumpT4(conditionalJumpT4Location, to, mayTriggerErrata)) {
- if (!mayTriggerErrata)
- return LinkConditionalJumpT4;
- }
+ if (canBeJumpT4(conditionalJumpT4Location, to))
+ return LinkConditionalJumpT4;
} else {
// 2-byte unconditional T2
const uint16_t* jumpT2Location = reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT2)));
@@ -1955,10 +1962,8 @@ public:
return LinkJumpT2;
// 4-byte unconditional T4
const uint16_t* jumpT4Location = reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT4)));
- if (canBeJumpT4(jumpT4Location, to, mayTriggerErrata)) {
- if (!mayTriggerErrata)
- return LinkJumpT4;
- }
+ if (canBeJumpT4(jumpT4Location, to))
+ return LinkJumpT4;
// use long jump sequence
return LinkBX;
}
@@ -2057,12 +2062,12 @@ public:
ASSERT(from.isSet());
ASSERT(reinterpret_cast<intptr_t>(to) & 1);
- setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to);
+ setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to, false);
}
static void linkPointer(void* code, AssemblerLabel where, void* value)
{
- setPointer(reinterpret_cast<char*>(code) + where.m_offset, value);
+ setPointer(reinterpret_cast<char*>(code) + where.m_offset, value, false);
}
static void relinkJump(void* from, void* to)
@@ -2080,7 +2085,7 @@ public:
ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
ASSERT(reinterpret_cast<intptr_t>(to) & 1);
- setPointer(reinterpret_cast<uint16_t*>(from) - 1, to);
+ setPointer(reinterpret_cast<uint16_t*>(from) - 1, to, true);
}
static void* readCallTarget(void* from)
@@ -2092,7 +2097,7 @@ public:
{
ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
- setInt32(where, value);
+ setInt32(where, value, true);
}
static void repatchCompact(void* where, int32_t offset)
@@ -2119,7 +2124,7 @@ public:
{
ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
- setPointer(where, value);
+ setPointer(where, value, true);
}
static void* readPointer(void* where)
@@ -2133,22 +2138,13 @@ public:
ASSERT(!(bitwise_cast<uintptr_t>(to) & 1));
uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 2;
- // Ensure that we're not in one of those errata-triggering thingies. If we are, then
- // prepend a nop.
- bool spansTwo4K = ((reinterpret_cast<intptr_t>(ptr) & 0xfff) == 0x002);
-
- if (spansTwo4K) {
- ptr[-2] = OP_NOP_T1;
- ptr++;
- }
-
linkJumpT4(ptr, to);
cacheFlush(ptr - 2, sizeof(uint16_t) * 2);
}
static ptrdiff_t maxJumpReplacementSize()
{
- return 6;
+ return 4;
}
static void replaceWithLoad(void* instructionStart)
@@ -2164,11 +2160,11 @@ public:
ptr[0] |= OP_LDR_imm_T3;
ptr[1] |= (ptr[1] & 0x0F00) << 4;
ptr[1] &= 0xF0FF;
+ cacheFlush(ptr, sizeof(uint16_t) * 2);
break;
default:
ASSERT_NOT_REACHED();
}
- cacheFlush(ptr, sizeof(uint16_t) * 2);
}
static void replaceWithAddressComputation(void* instructionStart)
@@ -2182,13 +2178,13 @@ public:
ptr[0] |= OP_ADD_imm_T3;
ptr[1] |= (ptr[1] & 0xF000) >> 4;
ptr[1] &= 0x0FFF;
+ cacheFlush(ptr, sizeof(uint16_t) * 2);
break;
case OP_ADD_imm_T3:
break;
default:
ASSERT_NOT_REACHED();
}
- cacheFlush(ptr, sizeof(uint16_t) * 2);
}
unsigned debugOffset() { return m_formatter.debugOffset(); }
@@ -2291,7 +2287,7 @@ private:
return VFPOperand(op);
}
- static void setInt32(void* code, uint32_t value)
+ static void setInt32(void* code, uint32_t value, bool flush)
{
uint16_t* location = reinterpret_cast<uint16_t*>(code);
ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2));
@@ -2303,7 +2299,8 @@ private:
location[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
location[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-1] >> 8) & 0xf, hi16);
- cacheFlush(location - 4, 4 * sizeof(uint16_t));
+ if (flush)
+ cacheFlush(location - 4, 4 * sizeof(uint16_t));
}
static int32_t readInt32(void* code)
@@ -2334,9 +2331,9 @@ private:
cacheFlush(location, sizeof(uint16_t));
}
- static void setPointer(void* code, void* value)
+ static void setPointer(void* code, void* value, bool flush)
{
- setInt32(code, reinterpret_cast<uint32_t>(value));
+ setInt32(code, reinterpret_cast<uint32_t>(value), flush);
}
static bool isB(void* address)
@@ -2401,46 +2398,22 @@ private:
return ((relative << 20) >> 20) == relative;
}
- static bool canBeJumpT3(const uint16_t* instruction, const void* target, bool& mayTriggerErrata)
+ static bool canBeJumpT3(const uint16_t* instruction, const void* target)
{
ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
- // From Cortex-A8 errata:
- // If the 32-bit Thumb-2 branch instruction spans two 4KiB regions and
- // the target of the branch falls within the first region it is
- // possible for the processor to incorrectly determine the branch
- // instruction, and it is also possible in some cases for the processor
- // to enter a deadlock state.
- // The instruction is spanning two pages if it ends at an address ending 0x002
- bool spansTwo4K = ((reinterpret_cast<intptr_t>(instruction) & 0xfff) == 0x002);
- mayTriggerErrata = spansTwo4K;
- // The target is in the first page if the jump branch back by [3..0x1002] bytes
- bool targetInFirstPage = (relative >= -0x1002) && (relative < -2);
- bool wouldTriggerA8Errata = spansTwo4K && targetInFirstPage;
- return ((relative << 11) >> 11) == relative && !wouldTriggerA8Errata;
+ return ((relative << 11) >> 11) == relative;
}
- static bool canBeJumpT4(const uint16_t* instruction, const void* target, bool& mayTriggerErrata)
+ static bool canBeJumpT4(const uint16_t* instruction, const void* target)
{
ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
- // From Cortex-A8 errata:
- // If the 32-bit Thumb-2 branch instruction spans two 4KiB regions and
- // the target of the branch falls within the first region it is
- // possible for the processor to incorrectly determine the branch
- // instruction, and it is also possible in some cases for the processor
- // to enter a deadlock state.
- // The instruction is spanning two pages if it ends at an address ending 0x002
- bool spansTwo4K = ((reinterpret_cast<intptr_t>(instruction) & 0xfff) == 0x002);
- mayTriggerErrata = spansTwo4K;
- // The target is in the first page if the jump branch back by [3..0x1002] bytes
- bool targetInFirstPage = (relative >= -0x1002) && (relative < -2);
- bool wouldTriggerA8Errata = spansTwo4K && targetInFirstPage;
- return ((relative << 7) >> 7) == relative && !wouldTriggerA8Errata;
+ return ((relative << 7) >> 7) == relative;
}
void linkJumpT1(Condition cond, uint16_t* instruction, void* target)
@@ -2484,9 +2457,7 @@ private:
// FIMXE: this should be up in the MacroAssembler layer. :-(
ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
- bool scratch;
- UNUSED_PARAM(scratch);
- ASSERT(canBeJumpT3(instruction, target, scratch));
+ ASSERT(canBeJumpT3(instruction, target));
intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
@@ -2501,9 +2472,7 @@ private:
// FIMXE: this should be up in the MacroAssembler layer. :-(
ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
- bool scratch;
- UNUSED_PARAM(scratch);
- ASSERT(canBeJumpT4(instruction, target, scratch));
+ ASSERT(canBeJumpT4(instruction, target));
intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
// ARM encoding for the top two bits below the sign bit is 'peculiar'.
@@ -2561,8 +2530,7 @@ private:
ASSERT((isMOV_imm_T3(instruction - 5) && isMOVT(instruction - 3) && isBX(instruction - 1))
|| (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2)));
- bool scratch;
- if (canBeJumpT4(instruction, target, scratch)) {
+ if (canBeJumpT4(instruction, target)) {
// There may be a better way to fix this, but right now put the NOPs first, since in the
// case of an conditional branch this will be coming after an ITTT predicating *three*
// instructions! Looking backwards to modify the ITTT to an IT is not easy, due to
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/LinkBuffer.cpp b/Source/JavaScriptCore/assembler/LinkBuffer.cpp
index 0176e4307..c269157ba 100644
--- a/Source/JavaScriptCore/assembler/LinkBuffer.cpp
+++ b/Source/JavaScriptCore/assembler/LinkBuffer.cpp
@@ -45,16 +45,15 @@ LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithDisassembly(const char* format,
CodeRef result = finalizeCodeWithoutDisassembly();
- dataLog("Generated JIT code for ");
+ dataLogF("Generated JIT code for ");
va_list argList;
va_start(argList, format);
- WTF::dataLogV(format, argList);
+ WTF::dataLogFV(format, argList);
va_end(argList);
- dataLog(":\n");
+ dataLogF(":\n");
- dataLog(" Code at [%p, %p):\n", result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size());
- if (!tryToDisassemble(result.code(), m_size, " ", WTF::dataFile()))
- dataLog(" <no disassembly available>\n");
+ dataLogF(" Code at [%p, %p):\n", result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size());
+ disassemble(result.code(), m_size, " ", WTF::dataFile());
return result;
}
@@ -169,11 +168,11 @@ void LinkBuffer::dumpLinkStatistics(void* code, size_t initializeSize, size_t fi
linkCount++;
totalInitialSize += initialSize;
totalFinalSize += finalSize;
- dataLog("link %p: orig %u, compact %u (delta %u, %.2f%%)\n",
+ dataLogF("link %p: orig %u, compact %u (delta %u, %.2f%%)\n",
code, static_cast<unsigned>(initialSize), static_cast<unsigned>(finalSize),
static_cast<unsigned>(initialSize - finalSize),
100.0 * (initialSize - finalSize) / initialSize);
- dataLog("\ttotal %u: orig %u, compact %u (delta %u, %.2f%%)\n",
+ dataLogF("\ttotal %u: orig %u, compact %u (delta %u, %.2f%%)\n",
linkCount, totalInitialSize, totalFinalSize, totalInitialSize - totalFinalSize,
100.0 * (totalInitialSize - totalFinalSize) / totalInitialSize);
}
@@ -192,7 +191,7 @@ void LinkBuffer::dumpCode(void* code, size_t size)
size_t tsize = size / sizeof(short);
char nameBuf[128];
snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++);
- dataLog("\t.syntax unified\n"
+ dataLogF("\t.syntax unified\n"
"\t.section\t__TEXT,__text,regular,pure_instructions\n"
"\t.globl\t%s\n"
"\t.align 2\n"
@@ -202,7 +201,7 @@ void LinkBuffer::dumpCode(void* code, size_t size)
"%s:\n", nameBuf, nameBuf, code, nameBuf);
for (unsigned i = 0; i < tsize; i++)
- dataLog("\t.short\t0x%x\n", tcode[i]);
+ dataLogF("\t.short\t0x%x\n", tcode[i]);
#elif CPU(ARM_TRADITIONAL)
// gcc -c jit.s
// objdump -D jit.o
@@ -211,7 +210,7 @@ void LinkBuffer::dumpCode(void* code, size_t size)
size_t tsize = size / sizeof(unsigned int);
char nameBuf[128];
snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++);
- dataLog("\t.globl\t%s\n"
+ dataLogF("\t.globl\t%s\n"
"\t.align 4\n"
"\t.code 32\n"
"\t.text\n"
@@ -219,7 +218,7 @@ void LinkBuffer::dumpCode(void* code, size_t size)
"%s:\n", nameBuf, code, nameBuf);
for (unsigned i = 0; i < tsize; i++)
- dataLog("\t.long\t0x%x\n", tcode[i]);
+ dataLogF("\t.long\t0x%x\n", tcode[i]);
#endif
}
#endif
diff --git a/Source/JavaScriptCore/assembler/LinkBuffer.h b/Source/JavaScriptCore/assembler/LinkBuffer.h
index 770144d64..e1882433c 100644
--- a/Source/JavaScriptCore/assembler/LinkBuffer.h
+++ b/Source/JavaScriptCore/assembler/LinkBuffer.h
@@ -263,9 +263,9 @@ private:
#endif
};
-#define FINALIZE_CODE_IF(condition, linkBufferReference, dataLogArgumentsForHeading) \
+#define FINALIZE_CODE_IF(condition, linkBufferReference, dataLogFArgumentsForHeading) \
(UNLIKELY((condition)) \
- ? ((linkBufferReference).finalizeCodeWithDisassembly dataLogArgumentsForHeading) \
+ ? ((linkBufferReference).finalizeCodeWithDisassembly dataLogFArgumentsForHeading) \
: (linkBufferReference).finalizeCodeWithoutDisassembly())
// Use this to finalize code, like so:
@@ -281,14 +281,14 @@ private:
//
// ... and so on.
//
-// Note that the dataLogArgumentsForHeading are only evaluated when showDisassembly
+// Note that the dataLogFArgumentsForHeading are only evaluated when showDisassembly
// is true, so you can hide expensive disassembly-only computations inside there.
-#define FINALIZE_CODE(linkBufferReference, dataLogArgumentsForHeading) \
- FINALIZE_CODE_IF(Options::showDisassembly(), linkBufferReference, dataLogArgumentsForHeading)
+#define FINALIZE_CODE(linkBufferReference, dataLogFArgumentsForHeading) \
+ FINALIZE_CODE_IF(Options::showDisassembly(), linkBufferReference, dataLogFArgumentsForHeading)
-#define FINALIZE_DFG_CODE(linkBufferReference, dataLogArgumentsForHeading) \
- FINALIZE_CODE_IF(Options::showDFGDisassembly(), linkBufferReference, dataLogArgumentsForHeading)
+#define FINALIZE_DFG_CODE(linkBufferReference, dataLogFArgumentsForHeading) \
+ FINALIZE_CODE_IF((Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, dataLogFArgumentsForHeading)
} // namespace JSC
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h
index 39d94adea..0ebdbda0c 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h
@@ -1266,6 +1266,19 @@ public:
return 0;
}
+ static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
+
+ static CodeLocationLabel startOfPatchableBranchPtrWithPatch(CodeLocationDataLabelPtr label)
+ {
+ UNREACHABLE_FOR_PLATFORM();
+ return CodeLocationLabel();
+ }
+
+ static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue)
+ {
+ UNREACHABLE_FOR_PLATFORM();
+ }
+
protected:
ARMAssembler::Condition ARMCondition(RelationalCondition cond)
{
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
index 1301038e5..8d7a3a69a 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
@@ -1758,6 +1758,30 @@ public:
{
return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
}
+
+ static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
+
+ static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
+ {
+ const unsigned twoWordOpSize = 4;
+ return label.labelAtOffset(-twoWordOpSize * 2);
+ }
+
+ static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue)
+ {
+ ARMv7Assembler::revertJumpTo_movT3(instructionStart.dataLocation(), dataTempRegister, ARMThumbImmediate::makeUInt16(reinterpret_cast<uintptr_t>(initialValue) & 0xffff));
+ }
+
+ static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
+ {
+ UNREACHABLE_FOR_PLATFORM();
+ return CodeLocationLabel();
+ }
+
+ static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*)
+ {
+ UNREACHABLE_FOR_PLATFORM();
+ }
protected:
ALWAYS_INLINE Jump jump()
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
index fc6f9f40d..5b6da9663 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
@@ -2242,6 +2242,20 @@ public:
return 0;
}
+ static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
+
+ static CodeLocationLabel startOfPatchableBranchPtrWithPatch(CodeLocationDataLabelPtr label)
+ {
+ UNREACHABLE_FOR_PLATFORM();
+ return CodeLocationLabel();
+ }
+
+ static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue)
+ {
+ UNREACHABLE_FOR_PLATFORM();
+ }
+
+
private:
// If m_fixedWidth is true, we will generate a fixed number of instructions.
// Otherwise, we can emit any number of instructions.
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86.h
index 8fd31466d..27a030edf 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86.h
@@ -253,6 +253,40 @@ public:
return FunctionPtr(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(call.dataLocation()) + offset));
}
+ static bool canJumpReplacePatchableBranchPtrWithPatch() { return true; }
+
+ static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
+ {
+ const int opcodeBytes = 1;
+ const int modRMBytes = 1;
+ const int immediateBytes = 4;
+ const int totalBytes = opcodeBytes + modRMBytes + immediateBytes;
+ ASSERT(totalBytes >= maxJumpReplacementSize());
+ return label.labelAtOffset(-totalBytes);
+ }
+
+ static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr label)
+ {
+ const int opcodeBytes = 1;
+ const int modRMBytes = 1;
+ const int offsetBytes = 0;
+ const int immediateBytes = 4;
+ const int totalBytes = opcodeBytes + modRMBytes + offsetBytes + immediateBytes;
+ ASSERT(totalBytes >= maxJumpReplacementSize());
+ return label.labelAtOffset(-totalBytes);
+ }
+
+ static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID reg, void* initialValue)
+ {
+ X86Assembler::revertJumpTo_cmpl_ir_force32(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), reg);
+ }
+
+ static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address address, void* initialValue)
+ {
+ ASSERT(!address.offset);
+ X86Assembler::revertJumpTo_cmpl_im_force32(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), 0, address.base);
+ }
+
private:
friend class LinkBuffer;
friend class RepatchBuffer;
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/MacroAssemblerX86_64.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
index ceacf6aa8..c711e6f8d 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
@@ -585,6 +585,33 @@ public:
static RegisterID scratchRegisterForBlinding() { return scratchRegister; }
+ static bool canJumpReplacePatchableBranchPtrWithPatch() { return true; }
+
+ static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
+ {
+ const int rexBytes = 1;
+ const int opcodeBytes = 1;
+ const int immediateBytes = 8;
+ const int totalBytes = rexBytes + opcodeBytes + immediateBytes;
+ ASSERT(totalBytes >= maxJumpReplacementSize());
+ return label.labelAtOffset(-totalBytes);
+ }
+
+ static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr label)
+ {
+ return startOfBranchPtrWithPatchOnRegister(label);
+ }
+
+ static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue)
+ {
+ X86Assembler::revertJumpTo_movq_i64r(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), scratchRegister);
+ }
+
+ static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue)
+ {
+ X86Assembler::revertJumpTo_movq_i64r(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), scratchRegister);
+ }
+
private:
friend class LinkBuffer;
friend class RepatchBuffer;
diff --git a/Source/JavaScriptCore/assembler/RepatchBuffer.h b/Source/JavaScriptCore/assembler/RepatchBuffer.h
index 531dda934..dbb56f9ad 100644
--- a/Source/JavaScriptCore/assembler/RepatchBuffer.h
+++ b/Source/JavaScriptCore/assembler/RepatchBuffer.h
@@ -141,6 +141,34 @@ public:
replaceWithAddressComputation(label);
}
+ static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
+ {
+ return MacroAssembler::startOfBranchPtrWithPatchOnRegister(label);
+ }
+
+ static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr label)
+ {
+ return MacroAssembler::startOfPatchableBranchPtrWithPatchOnAddress(label);
+ }
+
+ void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
+ {
+ MacroAssembler::replaceWithJump(instructionStart, destination);
+ }
+
+ // This is a *bit* of a silly API, since we currently always also repatch the
+ // immediate after calling this. But I'm fine with that, since this just feels
+ // less yucky.
+ void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, MacroAssembler::RegisterID reg, void* value)
+ {
+ MacroAssembler::revertJumpReplacementToBranchPtrWithPatch(instructionStart, reg, value);
+ }
+
+ void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, MacroAssembler::Address address, void* value)
+ {
+ MacroAssembler::revertJumpReplacementToPatchableBranchPtrWithPatch(instructionStart, address, value);
+ }
+
private:
void* m_start;
size_t m_size;
diff --git a/Source/JavaScriptCore/assembler/SH4Assembler.h b/Source/JavaScriptCore/assembler/SH4Assembler.h
index 373f469dc..3dbde2fa5 100644
--- a/Source/JavaScriptCore/assembler/SH4Assembler.h
+++ b/Source/JavaScriptCore/assembler/SH4Assembler.h
@@ -2070,7 +2070,7 @@ public:
static void vprintfStdoutInstr(const char* format, va_list args)
{
if (getenv("JavaScriptCoreDumpJIT"))
- WTF::dataLogV(format, args);
+ WTF::dataLogFV(format, args);
}
static void printBlockInstr(uint16_t* first, unsigned int offset, int nbInstr)
diff --git a/Source/JavaScriptCore/assembler/X86Assembler.h b/Source/JavaScriptCore/assembler/X86Assembler.h
index ecb178e88..25ff6f0a5 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));
@@ -1877,6 +1883,61 @@ public:
return 5;
}
+#if CPU(X86_64)
+ static void revertJumpTo_movq_i64r(void* instructionStart, int64_t imm, RegisterID dst)
+ {
+ const int rexBytes = 1;
+ const int opcodeBytes = 1;
+ ASSERT(rexBytes + opcodeBytes <= maxJumpReplacementSize());
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
+ ptr[0] = PRE_REX | (1 << 3) | (dst >> 3);
+ ptr[1] = OP_MOV_EAXIv | (dst & 7);
+
+ union {
+ uint64_t asWord;
+ uint8_t asBytes[8];
+ } u;
+ u.asWord = imm;
+ for (unsigned i = rexBytes + opcodeBytes; i < static_cast<unsigned>(maxJumpReplacementSize()); ++i)
+ ptr[i] = u.asBytes[i - rexBytes - opcodeBytes];
+ }
+#endif
+
+ static void revertJumpTo_cmpl_ir_force32(void* instructionStart, int32_t imm, RegisterID dst)
+ {
+ const int opcodeBytes = 1;
+ const int modRMBytes = 1;
+ ASSERT(opcodeBytes + modRMBytes <= maxJumpReplacementSize());
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
+ ptr[0] = OP_GROUP1_EvIz;
+ ptr[1] = (X86InstructionFormatter::ModRmRegister << 6) | (GROUP1_OP_CMP << 3) | dst;
+ union {
+ uint32_t asWord;
+ uint8_t asBytes[4];
+ } u;
+ u.asWord = imm;
+ for (unsigned i = opcodeBytes + modRMBytes; i < static_cast<unsigned>(maxJumpReplacementSize()); ++i)
+ ptr[i] = u.asBytes[i - opcodeBytes - modRMBytes];
+ }
+
+ static void revertJumpTo_cmpl_im_force32(void* instructionStart, int32_t imm, int offset, RegisterID dst)
+ {
+ ASSERT_UNUSED(offset, !offset);
+ const int opcodeBytes = 1;
+ const int modRMBytes = 1;
+ ASSERT(opcodeBytes + modRMBytes <= maxJumpReplacementSize());
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
+ ptr[0] = OP_GROUP1_EvIz;
+ ptr[1] = (X86InstructionFormatter::ModRmMemoryNoDisp << 6) | (GROUP1_OP_CMP << 3) | dst;
+ union {
+ uint32_t asWord;
+ uint8_t asBytes[4];
+ } u;
+ u.asWord = imm;
+ for (unsigned i = opcodeBytes + modRMBytes; i < static_cast<unsigned>(maxJumpReplacementSize()); ++i)
+ ptr[i] = u.asBytes[i - opcodeBytes - modRMBytes];
+ }
+
static void replaceWithLoad(void* instructionStart)
{
uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
@@ -1976,6 +2037,13 @@ private:
public:
+ enum ModRmMode {
+ ModRmMemoryNoDisp,
+ ModRmMemoryDisp8,
+ ModRmMemoryDisp32,
+ ModRmRegister,
+ };
+
// Legacy prefix bytes:
//
// These are emmitted prior to the instruction.
@@ -2314,6 +2382,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));
}
@@ -2343,13 +2414,6 @@ private:
inline void emitRexIfNeeded(int, int, int) {}
#endif
- enum ModRmMode {
- ModRmMemoryNoDisp,
- ModRmMemoryDisp8,
- ModRmMemoryDisp32,
- ModRmRegister,
- };
-
void putModRm(ModRmMode mode, int reg, RegisterID rm)
{
m_buffer.putByteUnchecked((mode << 6) | ((reg & 7) << 3) | (rm & 7));
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/CallLinkInfo.cpp b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
index 4933a494c..762dca12a 100644
--- a/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
+++ b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
@@ -37,6 +37,7 @@ void CallLinkInfo::unlink(JSGlobalData& globalData, RepatchBuffer& repatchBuffer
{
ASSERT(isLinked());
+ repatchBuffer.revertJumpReplacementToBranchPtrWithPatch(RepatchBuffer::startOfBranchPtrWithPatchOnRegister(hotPathBegin), static_cast<MacroAssembler::RegisterID>(calleeGPR), 0);
if (isDFG) {
#if ENABLE(DFG_JIT)
repatchBuffer.relink(callReturnLocation, (callType == Construct ? globalData.getCTIStub(DFG::linkConstructThunkGenerator) : globalData.getCTIStub(DFG::linkCallThunkGenerator)).code());
@@ -47,6 +48,7 @@ void CallLinkInfo::unlink(JSGlobalData& globalData, RepatchBuffer& repatchBuffer
repatchBuffer.relink(callReturnLocation, callType == Construct ? globalData.jitStubs->ctiVirtualConstructLink() : globalData.jitStubs->ctiVirtualCallLink());
hasSeenShouldRepatch = false;
callee.clear();
+ stub.clear();
// It will be on a list if the callee has a code block.
if (isOnList())
diff --git a/Source/JavaScriptCore/bytecode/CallLinkInfo.h b/Source/JavaScriptCore/bytecode/CallLinkInfo.h
index 4a78e5d02..89403b0ca 100644
--- a/Source/JavaScriptCore/bytecode/CallLinkInfo.h
+++ b/Source/JavaScriptCore/bytecode/CallLinkInfo.h
@@ -26,6 +26,7 @@
#ifndef CallLinkInfo_h
#define CallLinkInfo_h
+#include "ClosureCallStubRoutine.h"
#include "CodeLocation.h"
#include "JITWriteBarrier.h"
#include "JSFunction.h"
@@ -70,12 +71,14 @@ struct CallLinkInfo : public BasicRawSentinelNode<CallLinkInfo> {
CodeLocationNearCall hotPathOther;
JITWriteBarrier<JSFunction> callee;
WriteBarrier<JSFunction> lastSeenCallee;
+ RefPtr<ClosureCallStubRoutine> stub;
bool hasSeenShouldRepatch : 1;
bool isDFG : 1;
CallType callType : 6;
- unsigned bytecodeIndex;
+ unsigned calleeGPR : 8;
+ CodeOrigin codeOrigin;
- bool isLinked() { return callee; }
+ bool isLinked() { return stub || callee; }
void unlink(JSGlobalData&, RepatchBuffer&);
bool seenOnce()
@@ -96,7 +99,7 @@ inline void* getCallLinkInfoReturnLocation(CallLinkInfo* callLinkInfo)
inline unsigned getCallLinkInfoBytecodeIndex(CallLinkInfo* callLinkInfo)
{
- return callLinkInfo->bytecodeIndex;
+ return callLinkInfo->codeOrigin.bytecodeIndex;
}
#endif // ENABLE(JIT)
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 5686d5d2c..206d281a2 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -32,6 +32,7 @@
#include "BytecodeGenerator.h"
#include "DFGCapabilities.h"
+#include "DFGCommon.h"
#include "DFGNode.h"
#include "DFGRepatch.h"
#include "Debugger.h"
@@ -44,7 +45,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>
@@ -98,11 +99,11 @@ void CodeBlock::dumpBytecodeCommentAndNewLine(int location)
#if ENABLE(BYTECODE_COMMENTS)
const char* comment = commentForBytecodeOffset(location);
if (comment)
- dataLog("\t\t ; %s", comment);
+ dataLogF("\t\t ; %s", comment);
#else
UNUSED_PARAM(location);
#endif
- dataLog("\n");
+ dataLogF("\n");
}
CString CodeBlock::registerName(ExecState* exec, int r) const
@@ -163,33 +164,33 @@ NEVER_INLINE static const char* debugHookName(int debugHookID)
return "";
}
-void CodeBlock::printUnaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op)
+void CodeBlock::printUnaryOp(ExecState* exec, int location, const Instruction*& it, const char* op)
{
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
- dataLog("[%4d] %s\t\t %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data());
+ dataLogF("[%4d] %s\t\t %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data());
dumpBytecodeCommentAndNewLine(location);
}
-void CodeBlock::printBinaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op)
+void CodeBlock::printBinaryOp(ExecState* exec, int location, const Instruction*& it, const char* op)
{
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int r2 = (++it)->u.operand;
- dataLog("[%4d] %s\t\t %s, %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
+ dataLogF("[%4d] %s\t\t %s, %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
dumpBytecodeCommentAndNewLine(location);
}
-void CodeBlock::printConditionalJump(ExecState* exec, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator& it, int location, const char* op)
+void CodeBlock::printConditionalJump(ExecState* exec, const Instruction*, const Instruction*& it, int location, const char* op)
{
int r0 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] %s\t\t %s, %d(->%d)", location, op, registerName(exec, r0).data(), offset, location + offset);
+ dataLogF("[%4d] %s\t\t %s, %d(->%d)", location, op, registerName(exec, r0).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
}
-void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it)
+void CodeBlock::printGetByIdOp(ExecState* exec, int location, const Instruction*& it)
{
const char* op;
switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
@@ -242,7 +243,7 @@ void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int id0 = (++it)->u.operand;
- dataLog("[%4d] %s\t %s, %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
+ dataLogF("[%4d] %s\t %s, %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
it += 5;
}
@@ -252,18 +253,18 @@ static void dumpStructure(const char* name, ExecState* exec, Structure* structur
if (!structure)
return;
- dataLog("%s = %p", name, structure);
+ dataLogF("%s = %p", name, structure);
PropertyOffset offset = structure->get(exec->globalData(), ident);
if (offset != invalidOffset)
- dataLog(" (offset = %d)", offset);
+ dataLogF(" (offset = %d)", offset);
}
#endif
#if ENABLE(JIT) // unused when not ENABLE(JIT), leading to silly warnings
static void dumpChain(ExecState* exec, StructureChain* chain, Identifier& ident)
{
- dataLog("chain = %p: [", chain);
+ dataLogF("chain = %p: [", chain);
bool first = true;
for (WriteBarrier<Structure>* currentStructure = chain->head();
*currentStructure;
@@ -271,10 +272,10 @@ static void dumpChain(ExecState* exec, StructureChain* chain, Identifier& ident)
if (first)
first = false;
else
- dataLog(", ");
+ dataLogF(", ");
dumpStructure("struct", exec, currentStructure->get(), ident);
}
- dataLog("]");
+ dataLogF("]");
}
#endif
@@ -288,21 +289,21 @@ void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location)
#if ENABLE(LLINT)
if (exec->interpreter()->getOpcodeID(instruction[0].u.opcode) == op_get_array_length)
- dataLog(" llint(array_length)");
+ dataLogF(" llint(array_length)");
else {
Structure* structure = instruction[4].u.structure.get();
- dataLog(" llint(");
+ dataLogF(" llint(");
dumpStructure("struct", exec, structure, ident);
- dataLog(")");
+ dataLogF(")");
}
#endif
#if ENABLE(JIT)
if (numberOfStructureStubInfos()) {
- dataLog(" jit(");
+ dataLogF(" jit(");
StructureStubInfo& stubInfo = getStubInfo(location);
if (!stubInfo.seen)
- dataLog("not seen");
+ dataLogF("not seen");
else {
Structure* baseStructure = 0;
Structure* prototypeStructure = 0;
@@ -312,40 +313,40 @@ void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location)
switch (stubInfo.accessType) {
case access_get_by_id_self:
- dataLog("self");
+ dataLogF("self");
baseStructure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
break;
case access_get_by_id_proto:
- dataLog("proto");
+ dataLogF("proto");
baseStructure = stubInfo.u.getByIdProto.baseObjectStructure.get();
prototypeStructure = stubInfo.u.getByIdProto.prototypeStructure.get();
break;
case access_get_by_id_chain:
- dataLog("chain");
+ dataLogF("chain");
baseStructure = stubInfo.u.getByIdChain.baseObjectStructure.get();
chain = stubInfo.u.getByIdChain.chain.get();
break;
case access_get_by_id_self_list:
- dataLog("self_list");
+ dataLogF("self_list");
structureList = stubInfo.u.getByIdSelfList.structureList;
listSize = stubInfo.u.getByIdSelfList.listSize;
break;
case access_get_by_id_proto_list:
- dataLog("proto_list");
+ dataLogF("proto_list");
structureList = stubInfo.u.getByIdProtoList.structureList;
listSize = stubInfo.u.getByIdProtoList.listSize;
break;
case access_unset:
- dataLog("unset");
+ dataLogF("unset");
break;
case access_get_by_id_generic:
- dataLog("generic");
+ dataLogF("generic");
break;
case access_get_array_length:
- dataLog("array_length");
+ dataLogF("array_length");
break;
case access_get_string_length:
- dataLog("string_length");
+ dataLogF("string_length");
break;
default:
ASSERT_NOT_REACHED();
@@ -353,71 +354,71 @@ void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location)
}
if (baseStructure) {
- dataLog(", ");
+ dataLogF(", ");
dumpStructure("struct", exec, baseStructure, ident);
}
if (prototypeStructure) {
- dataLog(", ");
+ dataLogF(", ");
dumpStructure("prototypeStruct", exec, baseStructure, ident);
}
if (chain) {
- dataLog(", ");
+ dataLogF(", ");
dumpChain(exec, chain, ident);
}
if (structureList) {
- dataLog(", list = %p: [", structureList);
+ dataLogF(", list = %p: [", structureList);
for (int i = 0; i < listSize; ++i) {
if (i)
- dataLog(", ");
- dataLog("(");
+ dataLogF(", ");
+ dataLogF("(");
dumpStructure("base", exec, structureList->list[i].base.get(), ident);
if (structureList->list[i].isChain) {
if (structureList->list[i].u.chain.get()) {
- dataLog(", ");
+ dataLogF(", ");
dumpChain(exec, structureList->list[i].u.chain.get(), ident);
}
} else {
if (structureList->list[i].u.proto.get()) {
- dataLog(", ");
+ dataLogF(", ");
dumpStructure("proto", exec, structureList->list[i].u.proto.get(), ident);
}
}
- dataLog(")");
+ dataLogF(")");
}
- dataLog("]");
+ dataLogF("]");
}
}
- dataLog(")");
+ dataLogF(")");
}
#endif
}
-void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op, CacheDumpMode cacheDumpMode)
+void CodeBlock::printCallOp(ExecState* exec, int location, const Instruction*& it, const char* op, CacheDumpMode cacheDumpMode)
{
int func = (++it)->u.operand;
int argCount = (++it)->u.operand;
int registerOffset = (++it)->u.operand;
- dataLog("[%4d] %s\t %s, %d, %d", location, op, registerName(exec, func).data(), argCount, registerOffset);
+ dataLogF("[%4d] %s\t %s, %d, %d", location, op, registerName(exec, func).data(), argCount, registerOffset);
if (cacheDumpMode == DumpCaches) {
#if ENABLE(LLINT)
LLIntCallLinkInfo* callLinkInfo = it[1].u.callLinkInfo;
if (callLinkInfo->lastSeenCallee) {
- dataLog(" llint(%p, exec %p)",
+ dataLogF(" llint(%p, exec %p)",
callLinkInfo->lastSeenCallee.get(),
callLinkInfo->lastSeenCallee->executable());
} else
- dataLog(" llint(not set)");
+ dataLogF(" llint(not set)");
#endif
#if ENABLE(JIT)
if (numberOfCallLinkInfos()) {
JSFunction* target = getCallLinkInfo(location).lastSeenCallee.get();
if (target)
- dataLog(" jit(%p, exec %p)", target, target->executable());
+ dataLogF(" jit(%p, exec %p)", target, target->executable());
else
- dataLog(" jit(not set)");
+ dataLogF(" jit(not set)");
}
#endif
}
@@ -425,12 +426,12 @@ void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>::
it += 2;
}
-void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op)
+void CodeBlock::printPutByIdOp(ExecState* exec, int location, const Instruction*& it, const char* op)
{
int r0 = (++it)->u.operand;
int id0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
- dataLog("[%4d] %s\t %s, %s, %s", location, op, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
+ dataLogF("[%4d] %s\t %s, %s, %s", location, op, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
dumpBytecodeCommentAndNewLine(location);
it += 5;
}
@@ -438,7 +439,7 @@ void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction
void CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand)
{
unsigned instructionOffset = vPC - instructions().begin();
- dataLog(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).utf8().data());
+ dataLogF(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).utf8().data());
}
void CodeBlock::printStructures(const Instruction* vPC)
@@ -455,15 +456,15 @@ void CodeBlock::printStructures(const Instruction* vPC)
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
- dataLog(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data());
+ dataLogF(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data());
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
- dataLog(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data(), pointerToSourceString(vPC[6].u.structureChain).utf8().data());
+ dataLogF(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data(), pointerToSourceString(vPC[6].u.structureChain).utf8().data());
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
- dataLog(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structureChain).utf8().data());
+ dataLogF(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structureChain).utf8().data());
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id)) {
@@ -479,99 +480,103 @@ void CodeBlock::printStructures(const Instruction* vPC)
ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_call) || vPC[0].u.opcode == interpreter->getOpcode(op_call_eval) || vPC[0].u.opcode == interpreter->getOpcode(op_construct));
}
-void CodeBlock::dump(ExecState* exec)
+void CodeBlock::dump()
{
+ // We only use the ExecState* for things that don't actually lead to JS execution,
+ // like converting a JSString to a String. Hence the globalExec is appropriate.
+ ExecState* exec = m_globalObject->globalExec();
+
size_t instructionCount = 0;
for (size_t i = 0; i < instructions().size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(instructions()[i].u.opcode)])
++instructionCount;
- dataLog(
+ dataLogF(
"%lu m_instructions; %lu bytes at %p (%s); %d parameter(s); %d callee register(s); %d variable(s)",
static_cast<unsigned long>(instructions().size()),
static_cast<unsigned long>(instructions().size() * sizeof(Instruction)),
this, codeTypeToString(codeType()), m_numParameters, m_numCalleeRegisters,
m_numVars);
if (symbolTable()->captureCount())
- dataLog("; %d captured var(s)", symbolTable()->captureCount());
+ dataLogF("; %d captured var(s)", symbolTable()->captureCount());
if (usesArguments()) {
- dataLog(
+ dataLogF(
"; uses arguments, in r%d, r%d",
argumentsRegister(),
unmodifiedArgumentsRegister(argumentsRegister()));
}
if (needsFullScopeChain() && codeType() == FunctionCode)
- dataLog("; activation in r%d", activationRegister());
- dataLog("\n\n");
+ dataLogF("; activation in r%d", activationRegister());
+ dataLogF("\n\n");
- Vector<Instruction>::const_iterator begin = instructions().begin();
- Vector<Instruction>::const_iterator end = instructions().end();
- for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
+ const Instruction* begin = instructions().begin();
+ const Instruction* end = instructions().end();
+ for (const Instruction* it = begin; it != end; ++it)
dump(exec, begin, it);
if (!m_identifiers.isEmpty()) {
- dataLog("\nIdentifiers:\n");
+ dataLogF("\nIdentifiers:\n");
size_t i = 0;
do {
- dataLog(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].string().utf8().data());
+ dataLogF(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].string().utf8().data());
++i;
} while (i != m_identifiers.size());
}
if (!m_constantRegisters.isEmpty()) {
- dataLog("\nConstants:\n");
+ dataLogF("\nConstants:\n");
size_t i = 0;
do {
- dataLog(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, m_constantRegisters[i].get()).utf8().data());
+ dataLogF(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, m_constantRegisters[i].get()).utf8().data());
++i;
} while (i < m_constantRegisters.size());
}
if (size_t count = m_unlinkedCode->numberOfRegExps()) {
- dataLog("\nm_regexps:\n");
+ dataLogF("\nm_regexps:\n");
size_t i = 0;
do {
- dataLog(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_unlinkedCode->regexp(i)).utf8().data());
+ dataLogF(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_unlinkedCode->regexp(i)).utf8().data());
++i;
} while (i < count);
}
#if ENABLE(JIT)
if (!m_structureStubInfos.isEmpty())
- dataLog("\nStructures:\n");
+ dataLogF("\nStructures:\n");
#endif
if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
- dataLog("\nException Handlers:\n");
+ dataLogF("\nException Handlers:\n");
unsigned i = 0;
do {
- dataLog("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target);
+ dataLogF("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target);
++i;
} while (i < m_rareData->m_exceptionHandlers.size());
}
if (m_rareData && !m_rareData->m_immediateSwitchJumpTables.isEmpty()) {
- dataLog("Immediate Switch Jump Tables:\n");
+ dataLogF("Immediate Switch Jump Tables:\n");
unsigned i = 0;
do {
- dataLog(" %1d = {\n", i);
+ dataLogF(" %1d = {\n", i);
int entry = 0;
Vector<int32_t>::const_iterator end = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.end();
for (Vector<int32_t>::const_iterator iter = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
if (!*iter)
continue;
- dataLog("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter);
+ dataLogF("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter);
}
- dataLog(" }\n");
+ dataLogF(" }\n");
++i;
} while (i < m_rareData->m_immediateSwitchJumpTables.size());
}
if (m_rareData && !m_rareData->m_characterSwitchJumpTables.isEmpty()) {
- dataLog("\nCharacter Switch Jump Tables:\n");
+ dataLogF("\nCharacter Switch Jump Tables:\n");
unsigned i = 0;
do {
- dataLog(" %1d = {\n", i);
+ dataLogF(" %1d = {\n", i);
int entry = 0;
Vector<int32_t>::const_iterator end = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.end();
for (Vector<int32_t>::const_iterator iter = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
@@ -579,72 +584,79 @@ void CodeBlock::dump(ExecState* exec)
continue;
ASSERT(!((i + m_rareData->m_characterSwitchJumpTables[i].min) & ~0xFFFF));
UChar ch = static_cast<UChar>(entry + m_rareData->m_characterSwitchJumpTables[i].min);
- dataLog("\t\t\"%s\" => %04d\n", String(&ch, 1).utf8().data(), *iter);
+ dataLogF("\t\t\"%s\" => %04d\n", String(&ch, 1).utf8().data(), *iter);
}
- dataLog(" }\n");
+ dataLogF(" }\n");
++i;
} while (i < m_rareData->m_characterSwitchJumpTables.size());
}
if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) {
- dataLog("\nString Switch Jump Tables:\n");
+ dataLogF("\nString Switch Jump Tables:\n");
unsigned i = 0;
do {
- dataLog(" %1d = {\n", i);
+ dataLogF(" %1d = {\n", i);
StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end();
for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
- dataLog("\t\t\"%s\" => %04d\n", String(iter->key).utf8().data(), iter->value.branchOffset);
- dataLog(" }\n");
+ dataLogF("\t\t\"%s\" => %04d\n", String(iter->key).utf8().data(), iter->value.branchOffset);
+ dataLogF(" }\n");
++i;
} while (i < m_rareData->m_stringSwitchJumpTables.size());
}
- dataLog("\n");
+ dataLogF("\n");
}
-void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it)
+void CodeBlock::dump(ExecState* exec, const Instruction* begin, const Instruction*& it)
{
int location = it - begin;
switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
case op_enter: {
- dataLog("[%4d] enter", location);
+ dataLogF("[%4d] enter", location);
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_create_activation: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] create_activation %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] create_activation %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_create_arguments: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] create_arguments\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] create_arguments\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_init_lazy_reg: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] init_lazy_reg\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] init_lazy_reg\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
+ case op_get_callee: {
+ int r0 = (++it)->u.operand;
+ dataLogF("[%4d] op_get_callee %s\n", location, registerName(exec, r0).data());
+ ++it;
+ break;
+ }
case op_create_this: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] create_this %s", location, registerName(exec, r0).data());
+ int r1 = (++it)->u.operand;
+ dataLogF("[%4d] create_this %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_convert_this: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] convert_this\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] convert_this\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
++it; // Skip value profile.
break;
}
case op_new_object: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] new_object\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] new_object\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -652,40 +664,43 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int dst = (++it)->u.operand;
int argv = (++it)->u.operand;
int argc = (++it)->u.operand;
- dataLog("[%4d] new_array\t %s, %s, %d", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc);
+ dataLogF("[%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: {
int dst = (++it)->u.operand;
int length = (++it)->u.operand;
- dataLog("[%4d] new_array_with_size\t %s, %s", location, registerName(exec, dst).data(), registerName(exec, length).data());
+ dataLogF("[%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: {
int dst = (++it)->u.operand;
int argv = (++it)->u.operand;
int argc = (++it)->u.operand;
- dataLog("[%4d] new_array_buffer\t %s, %d, %d", location, registerName(exec, dst).data(), argv, argc);
+ dataLogF("[%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: {
int r0 = (++it)->u.operand;
int re0 = (++it)->u.operand;
- dataLog("[%4d] new_regexp\t %s, ", location, registerName(exec, r0).data());
+ dataLogF("[%4d] new_regexp\t %s, ", location, registerName(exec, r0).data());
if (r0 >=0 && r0 < (int)m_unlinkedCode->numberOfRegExps())
- dataLog("%s", regexpName(re0, regexp(re0)).data());
+ dataLogF("%s", regexpName(re0, regexp(re0)).data());
else
- dataLog("bad_regexp(%d)", re0);
+ dataLogF("bad_regexp(%d)", re0);
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_mov: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
- dataLog("[%4d] mov\t\t %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data());
+ dataLogF("[%4d] mov\t\t %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -735,13 +750,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
}
case op_pre_inc: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] pre_inc\t\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] pre_inc\t\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_pre_dec: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] pre_dec\t\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] pre_dec\t\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -817,7 +832,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r1 = (++it)->u.operand;
int r2 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] check_has_instance\t\t %s, %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), offset, location + offset);
+ dataLogF("[%4d] check_has_instance\t\t %s, %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -825,7 +840,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int r2 = (++it)->u.operand;
- dataLog("[%4d] instanceof\t\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
+ dataLogF("[%4d] instanceof\t\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -867,7 +882,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int id0 = (++it)->u.operand;
int value = (++it)->u.operand;
int resolveInfo = (++it)->u.operand;
- dataLog("[%4d] put_to_base\t %s, %s, %s, %d", location, registerName(exec, base).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, value).data(), resolveInfo);
+ dataLogF("[%4d] put_to_base\t %s, %s, %s, %d", location, registerName(exec, base).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, value).data(), resolveInfo);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -880,13 +895,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int id0 = (++it)->u.operand;
int resolveInfo = (++it)->u.operand;
- dataLog("[%4d] resolve\t\t %s, %s, %d", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo);
+ dataLogF("[%4d] resolve\t\t %s, %s, %d", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo);
dumpBytecodeCommentAndNewLine(location);
it++;
break;
}
case op_init_global_const_nop: {
- dataLog("[%4d] init_global_const_nop\t", location);
+ dataLogF("[%4d] init_global_const_nop\t", location);
dumpBytecodeCommentAndNewLine(location);
it++;
it++;
@@ -897,7 +912,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
case op_init_global_const: {
WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
int r0 = (++it)->u.operand;
- dataLog("[%4d] init_global_const\t g%d(%p), %s", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data());
+ dataLogF("[%4d] init_global_const\t g%d(%p), %s", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
it++;
it++;
@@ -906,7 +921,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
case op_init_global_const_check: {
WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
int r0 = (++it)->u.operand;
- dataLog("[%4d] init_global_const_check\t g%d(%p), %s", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data());
+ dataLogF("[%4d] init_global_const_check\t g%d(%p), %s", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
it++;
it++;
@@ -922,7 +937,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int isStrict = (++it)->u.operand;
int resolveInfo = (++it)->u.operand;
int putToBaseInfo = (++it)->u.operand;
- dataLog("[%4d] resolve_base%s\t %s, %s, %d, %d", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo);
+ dataLogF("[%4d] resolve_base%s\t %s, %s, %d, %d", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo);
dumpBytecodeCommentAndNewLine(location);
it++;
break;
@@ -930,7 +945,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
case op_ensure_property_exists: {
int r0 = (++it)->u.operand;
int id0 = (++it)->u.operand;
- dataLog("[%4d] ensure_property_exists\t %s, %s", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
+ dataLogF("[%4d] ensure_property_exists\t %s, %s", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -940,7 +955,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int id0 = (++it)->u.operand;
int resolveInfo = (++it)->u.operand;
int putToBaseInfo = (++it)->u.operand;
- dataLog("[%4d] resolve_with_base %s, %s, %s, %d, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo);
+ dataLogF("[%4d] resolve_with_base %s, %s, %s, %d, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo);
dumpBytecodeCommentAndNewLine(location);
it++;
break;
@@ -950,7 +965,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r1 = (++it)->u.operand;
int id0 = (++it)->u.operand;
int resolveInfo = (++it)->u.operand;
- dataLog("[%4d] resolve_with_this %s, %s, %s, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo);
+ dataLogF("[%4d] resolve_with_this %s, %s, %s, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo);
dumpBytecodeCommentAndNewLine(location);
it++;
break;
@@ -1020,7 +1035,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int id0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int r2 = (++it)->u.operand;
- dataLog("[%4d] put_getter_setter\t %s, %s, %s, %s", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
+ dataLogF("[%4d] put_getter_setter\t %s, %s, %s, %s", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1028,7 +1043,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int id0 = (++it)->u.operand;
- dataLog("[%4d] del_by_id\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
+ dataLogF("[%4d] del_by_id\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1036,7 +1051,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int r2 = (++it)->u.operand;
- dataLog("[%4d] get_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
+ dataLogF("[%4d] get_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
dumpBytecodeCommentAndNewLine(location);
it++;
it++;
@@ -1046,7 +1061,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int r2 = (++it)->u.operand;
- dataLog("[%4d] get_argument_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
+ dataLogF("[%4d] get_argument_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
dumpBytecodeCommentAndNewLine(location);
++it;
++it;
@@ -1059,7 +1074,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r3 = (++it)->u.operand;
int r4 = (++it)->u.operand;
int r5 = (++it)->u.operand;
- dataLog("[%4d] get_by_pname\t %s, %s, %s, %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), registerName(exec, r4).data(), registerName(exec, r5).data());
+ dataLogF("[%4d] get_by_pname\t %s, %s, %s, %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), registerName(exec, r4).data(), registerName(exec, r5).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1067,7 +1082,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int r2 = (++it)->u.operand;
- dataLog("[%4d] put_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
+ dataLogF("[%4d] put_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
dumpBytecodeCommentAndNewLine(location);
++it;
break;
@@ -1076,7 +1091,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int r2 = (++it)->u.operand;
- dataLog("[%4d] del_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
+ dataLogF("[%4d] del_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1084,19 +1099,19 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
unsigned n0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
- dataLog("[%4d] put_by_index\t %s, %u, %s", location, registerName(exec, r0).data(), n0, registerName(exec, r1).data());
+ dataLogF("[%4d] put_by_index\t %s, %u, %s", location, registerName(exec, r0).data(), n0, registerName(exec, r1).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_jmp: {
int offset = (++it)->u.operand;
- dataLog("[%4d] jmp\t\t %d(->%d)", location, offset, location + offset);
+ dataLogF("[%4d] jmp\t\t %d(->%d)", location, offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_loop: {
int offset = (++it)->u.operand;
- dataLog("[%4d] loop\t\t %d(->%d)", location, offset, location + offset);
+ dataLogF("[%4d] loop\t\t %d(->%d)", location, offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1128,7 +1143,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
Special::Pointer pointer = (++it)->u.specialPointer;
int offset = (++it)->u.operand;
- dataLog("[%4d] jneq_ptr\t\t %s, %d (%p), %d(->%d)", location, registerName(exec, r0).data(), pointer, m_globalObject->actualPointerFor(pointer), offset, location + offset);
+ dataLogF("[%4d] jneq_ptr\t\t %s, %d (%p), %d(->%d)", location, registerName(exec, r0).data(), pointer, m_globalObject->actualPointerFor(pointer), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1136,7 +1151,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] jless\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] jless\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1144,7 +1159,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] jlesseq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] jlesseq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1152,7 +1167,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] jgreater\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] jgreater\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1160,7 +1175,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] jgreatereq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] jgreatereq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1168,7 +1183,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] jnless\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] jnless\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1176,7 +1191,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] jnlesseq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] jnlesseq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1184,7 +1199,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] jngreater\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] jngreater\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1192,7 +1207,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] jngreatereq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] jngreatereq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1200,7 +1215,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] loop_if_less\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] loop_if_less\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1208,7 +1223,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1216,7 +1231,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] loop_if_greater\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] loop_if_greater\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1224,12 +1239,12 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] loop_if_greatereq\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
+ dataLogF("[%4d] loop_if_greatereq\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_loop_hint: {
- dataLog("[%4d] loop_hint", location);
+ dataLogF("[%4d] loop_hint", location);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1237,7 +1252,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int tableIndex = (++it)->u.operand;
int defaultTarget = (++it)->u.operand;
int scrutineeRegister = (++it)->u.operand;
- dataLog("[%4d] switch_imm\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
+ dataLogF("[%4d] switch_imm\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1245,7 +1260,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int tableIndex = (++it)->u.operand;
int defaultTarget = (++it)->u.operand;
int scrutineeRegister = (++it)->u.operand;
- dataLog("[%4d] switch_char\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
+ dataLogF("[%4d] switch_char\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1253,7 +1268,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int tableIndex = (++it)->u.operand;
int defaultTarget = (++it)->u.operand;
int scrutineeRegister = (++it)->u.operand;
- dataLog("[%4d] switch_string\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
+ dataLogF("[%4d] switch_string\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1261,14 +1276,14 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int f0 = (++it)->u.operand;
int shouldCheck = (++it)->u.operand;
- dataLog("[%4d] new_func\t\t %s, f%d, %s", location, registerName(exec, r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>");
+ dataLogF("[%4d] new_func\t\t %s, f%d, %s", location, registerName(exec, r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>");
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_new_func_exp: {
int r0 = (++it)->u.operand;
int f0 = (++it)->u.operand;
- dataLog("[%4d] new_func_exp\t %s, f%d", location, registerName(exec, r0).data(), f0);
+ dataLogF("[%4d] new_func_exp\t %s, f%d", location, registerName(exec, r0).data(), f0);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1285,32 +1300,32 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int thisValue = (++it)->u.operand;
int arguments = (++it)->u.operand;
int firstFreeRegister = (++it)->u.operand;
- dataLog("[%4d] call_varargs\t %s, %s, %s, %d", location, registerName(exec, callee).data(), registerName(exec, thisValue).data(), registerName(exec, arguments).data(), firstFreeRegister);
+ dataLogF("[%4d] call_varargs\t %s, %s, %s, %d", location, registerName(exec, callee).data(), registerName(exec, thisValue).data(), registerName(exec, arguments).data(), firstFreeRegister);
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_tear_off_activation: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] tear_off_activation\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] tear_off_activation\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_tear_off_arguments: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
- dataLog("[%4d] tear_off_arguments %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data());
+ dataLogF("[%4d] tear_off_arguments %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_ret: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] ret\t\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] ret\t\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_call_put_result: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] call_put_result\t\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] call_put_result\t\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
it++;
break;
@@ -1318,7 +1333,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
case op_ret_object_or_this: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
- dataLog("[%4d] constructor_ret\t\t %s %s", location, registerName(exec, r0).data(), registerName(exec, r1).data());
+ dataLogF("[%4d] constructor_ret\t\t %s %s", location, registerName(exec, r0).data(), registerName(exec, r1).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1330,14 +1345,14 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int count = (++it)->u.operand;
- dataLog("[%4d] strcat\t\t %s, %s, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), count);
+ dataLogF("[%4d] strcat\t\t %s, %s, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), count);
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_to_primitive: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
- dataLog("[%4d] to_primitive\t %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data());
+ dataLogF("[%4d] to_primitive\t %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1347,7 +1362,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r2 = it[3].u.operand;
int r3 = it[4].u.operand;
int offset = it[5].u.operand;
- dataLog("[%4d] get_pnames\t %s, %s, %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), offset, location + offset);
+ dataLogF("[%4d] get_pnames\t %s, %s, %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
it += OPCODE_LENGTH(op_get_pnames) - 1;
break;
@@ -1359,19 +1374,19 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int size = it[4].u.operand;
int iter = it[5].u.operand;
int offset = it[6].u.operand;
- dataLog("[%4d] next_pname\t %s, %s, %s, %s, %s, %d(->%d)", location, registerName(exec, dest).data(), registerName(exec, base).data(), registerName(exec, i).data(), registerName(exec, size).data(), registerName(exec, iter).data(), offset, location + offset);
+ dataLogF("[%4d] next_pname\t %s, %s, %s, %s, %s, %d(->%d)", location, registerName(exec, dest).data(), registerName(exec, base).data(), registerName(exec, i).data(), registerName(exec, size).data(), registerName(exec, iter).data(), offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
it += OPCODE_LENGTH(op_next_pname) - 1;
break;
}
case op_push_with_scope: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] push_with_scope\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] push_with_scope\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_pop_scope: {
- dataLog("[%4d] pop_scope", location);
+ dataLogF("[%4d] pop_scope", location);
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1379,33 +1394,33 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int id0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
unsigned attributes = (++it)->u.operand;
- dataLog("[%4d] push_name_scope \t%s, %s, %u", location, idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), attributes);
+ dataLogF("[%4d] push_name_scope \t%s, %s, %u", location, idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), attributes);
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_jmp_scopes: {
int scopeDelta = (++it)->u.operand;
int offset = (++it)->u.operand;
- dataLog("[%4d] jmp_scopes\t^%d, %d(->%d)", location, scopeDelta, offset, location + offset);
+ dataLogF("[%4d] jmp_scopes\t^%d, %d(->%d)", location, scopeDelta, offset, location + offset);
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_catch: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] catch\t\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] catch\t\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_throw: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] throw\t\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] throw\t\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_throw_static_error: {
int k0 = (++it)->u.operand;
int k1 = (++it)->u.operand;
- dataLog("[%4d] throw_static_error\t %s, %s", location, constantName(exec, k0, getConstant(k0)).data(), k1 ? "true" : "false");
+ dataLogF("[%4d] throw_static_error\t %s, %s", location, constantName(exec, k0, getConstant(k0)).data(), k1 ? "true" : "false");
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1414,25 +1429,25 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int firstLine = (++it)->u.operand;
int lastLine = (++it)->u.operand;
int column = (++it)->u.operand;
- dataLog("[%4d] debug\t\t %s, %d, %d, %d", location, debugHookName(debugHookID), firstLine, lastLine, column);
+ dataLogF("[%4d] debug\t\t %s, %d, %d, %d", location, debugHookName(debugHookID), firstLine, lastLine, column);
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_profile_will_call: {
int function = (++it)->u.operand;
- dataLog("[%4d] profile_will_call %s", location, registerName(exec, function).data());
+ dataLogF("[%4d] profile_will_call %s", location, registerName(exec, function).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_profile_did_call: {
int function = (++it)->u.operand;
- dataLog("[%4d] profile_did_call\t %s", location, registerName(exec, function).data());
+ dataLogF("[%4d] profile_did_call\t %s", location, registerName(exec, function).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
case op_end: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] end\t\t %s", location, registerName(exec, r0).data());
+ dataLogF("[%4d] end\t\t %s", location, registerName(exec, r0).data());
dumpBytecodeCommentAndNewLine(location);
break;
}
@@ -1443,6 +1458,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
}
}
+void CodeBlock::dump(unsigned bytecodeOffset)
+{
+ ExecState* exec = m_globalObject->globalExec();
+ const Instruction* it = instructions().begin() + bytecodeOffset;
+ dump(exec, instructions().begin(), it);
+}
+
#if DUMP_CODE_BLOCK_STATISTICS
static HashSet<CodeBlock*> liveCodeBlockSet;
#endif
@@ -1541,29 +1563,29 @@ void CodeBlock::dumpStatistics()
totalSize += symbolTableTotalSize;
totalSize += (liveCodeBlockSet.size() * sizeof(CodeBlock));
- dataLog("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size());
- dataLog("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock));
- dataLog("Size of all CodeBlocks: %zu\n", totalSize);
- dataLog("Average size of a CodeBlock: %zu\n", totalSize / liveCodeBlockSet.size());
+ dataLogF("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size());
+ dataLogF("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock));
+ dataLogF("Size of all CodeBlocks: %zu\n", totalSize);
+ dataLogF("Average size of a CodeBlock: %zu\n", totalSize / liveCodeBlockSet.size());
- dataLog("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode, static_cast<double>(isFunctionCode) * 100.0 / liveCodeBlockSet.size());
- dataLog("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size());
- dataLog("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size());
+ dataLogF("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode, static_cast<double>(isFunctionCode) * 100.0 / liveCodeBlockSet.size());
+ dataLogF("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size());
+ dataLogF("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size());
- dataLog("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size());
+ dataLogF("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size());
- #define PRINT_STATS(name) dataLog("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); dataLog("Size of all " #name ": %zu\n", name##TotalSize);
+ #define PRINT_STATS(name) dataLogF("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); dataLogF("Size of all " #name ": %zu\n", name##TotalSize);
FOR_EACH_MEMBER_VECTOR(PRINT_STATS)
FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS)
#undef PRINT_STATS
- dataLog("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty);
- dataLog("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty);
+ dataLogF("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty);
+ dataLogF("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty);
- dataLog("Size of all symbolTables: %zu\n", symbolTableTotalSize);
+ dataLogF("Size of all symbolTables: %zu\n", symbolTableTotalSize);
#else
- dataLog("Dumping CodeBlock statistics is not enabled.\n");
+ dataLogF("Dumping CodeBlock statistics is not enabled.\n");
#endif
}
@@ -1746,6 +1768,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
@@ -1786,7 +1810,8 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
case op_resolve_with_base:
case op_resolve_with_this:
case op_get_by_id:
- case op_call_put_result: {
+ case op_call_put_result:
+ case op_get_callee: {
ValueProfile* profile = &m_valueProfiles[pc[i + opLength - 1].u.operand];
ASSERT(profile->m_bytecodeOffset == -1);
profile->m_bytecodeOffset = i;
@@ -1800,22 +1825,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
-#if !ENABLE(LLINT)
- break;
-#endif
- }
#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:
@@ -1857,7 +1892,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
m_instructions = WTF::RefCountedArray<Instruction>(instructions);
if (BytecodeGenerator::dumpsGeneratedCode())
- dump(m_globalObject->globalExec());
+ dump();
m_globalData->finishedCompiling(this);
}
@@ -2118,7 +2153,7 @@ void CodeBlock::finalizeUnconditionally()
if (!curInstruction[4].u.structure || Heap::isMarked(curInstruction[4].u.structure.get()))
break;
if (verboseUnlinking)
- dataLog("Clearing LLInt property access with structure %p.\n", curInstruction[4].u.structure.get());
+ dataLogF("Clearing LLInt property access with structure %p.\n", curInstruction[4].u.structure.get());
curInstruction[4].u.structure.clear();
curInstruction[5].u.operand = 0;
break;
@@ -2131,7 +2166,7 @@ void CodeBlock::finalizeUnconditionally()
&& Heap::isMarked(curInstruction[7].u.structureChain.get()))
break;
if (verboseUnlinking) {
- dataLog("Clearing LLInt put transition with structures %p -> %p, chain %p.\n",
+ dataLogF("Clearing LLInt put transition with structures %p -> %p, chain %p.\n",
curInstruction[4].u.structure.get(),
curInstruction[6].u.structure.get(),
curInstruction[7].u.structureChain.get());
@@ -2151,7 +2186,7 @@ void CodeBlock::finalizeUnconditionally()
for (unsigned i = 0; i < m_llintCallLinkInfos.size(); ++i) {
if (m_llintCallLinkInfos[i].isLinked() && !Heap::isMarked(m_llintCallLinkInfos[i].callee.get())) {
if (verboseUnlinking)
- dataLog("Clearing LLInt call from %p.\n", this);
+ dataLogF("Clearing LLInt call from %p.\n", this);
m_llintCallLinkInfos[i].unlink();
}
if (!!m_llintCallLinkInfos[i].lastSeenCallee && !Heap::isMarked(m_llintCallLinkInfos[i].lastSeenCallee.get()))
@@ -2164,12 +2199,33 @@ void CodeBlock::finalizeUnconditionally()
// Check if we're not live. If we are, then jettison.
if (!(shouldImmediatelyAssumeLivenessDuringScan() || m_dfgData->livenessHasBeenProved)) {
if (verboseUnlinking)
- dataLog("Code block %p has dead weak references, jettisoning during GC.\n", this);
+ dataLogF("Code block %p (executable %p) has dead weak references, jettisoning during GC.\n", this, ownerExecutable());
// Make sure that the baseline JIT knows that it should re-warm-up before
// optimizing.
alternative()->optimizeAfterWarmUp();
+ if (DFG::shouldShowDisassembly()) {
+ dataLogF("DFG CodeBlock %p will be jettisoned because of the following dead references:\n", this);
+ for (unsigned i = 0; i < m_dfgData->transitions.size(); ++i) {
+ WeakReferenceTransition& transition = m_dfgData->transitions[i];
+ JSCell* origin = transition.m_codeOrigin.get();
+ JSCell* from = transition.m_from.get();
+ JSCell* to = transition.m_to.get();
+ if ((!origin || Heap::isMarked(origin)) && Heap::isMarked(from))
+ continue;
+ dataLogF(" Transition under %s, ", JSValue(origin).description());
+ dataLogF("%s -> ", JSValue(from).description());
+ dataLogF("%s.\n", JSValue(to).description());
+ }
+ for (unsigned i = 0; i < m_dfgData->weakReferences.size(); ++i) {
+ JSCell* weak = m_dfgData->weakReferences[i].get();
+ if (Heap::isMarked(weak))
+ continue;
+ dataLogF(" Weak reference %s.\n", JSValue(weak).description());
+ }
+ }
+
jettison();
return;
}
@@ -2178,7 +2234,7 @@ void CodeBlock::finalizeUnconditionally()
for (size_t size = m_putToBaseOperations.size(), i = 0; i < size; ++i) {
if (m_putToBaseOperations[i].m_structure && !Heap::isMarked(m_putToBaseOperations[i].m_structure.get())) {
if (verboseUnlinking)
- dataLog("Clearing putToBase info in %p.\n", this);
+ dataLogF("Clearing putToBase info in %p.\n", this);
m_putToBaseOperations[i].m_structure.clear();
}
}
@@ -2192,7 +2248,7 @@ void CodeBlock::finalizeUnconditionally()
m_resolveOperations[i].last().m_structure.clear();
if (m_resolveOperations[i].last().m_structure && !Heap::isMarked(m_resolveOperations[i].last().m_structure.get())) {
if (verboseUnlinking)
- dataLog("Clearing resolve info in %p.\n", this);
+ dataLogF("Clearing resolve info in %p.\n", this);
m_resolveOperations[i].last().m_structure.clear();
}
}
@@ -2202,10 +2258,19 @@ void CodeBlock::finalizeUnconditionally()
if (!!getJITCode()) {
RepatchBuffer repatchBuffer(this);
for (unsigned i = 0; i < numberOfCallLinkInfos(); ++i) {
- if (callLinkInfo(i).isLinked() && !Heap::isMarked(callLinkInfo(i).callee.get())) {
- if (verboseUnlinking)
- dataLog("Clearing call from %p to %p.\n", this, callLinkInfo(i).callee.get());
- callLinkInfo(i).unlink(*m_globalData, repatchBuffer);
+ if (callLinkInfo(i).isLinked()) {
+ if (ClosureCallStubRoutine* stub = callLinkInfo(i).stub.get()) {
+ if (!Heap::isMarked(stub->structure())
+ || !Heap::isMarked(stub->executable())) {
+ if (verboseUnlinking)
+ dataLogF("Clearing closure call from %p to %p, stub routine %p.\n", this, stub->executable(), stub);
+ callLinkInfo(i).unlink(*m_globalData, repatchBuffer);
+ }
+ } else if (!Heap::isMarked(callLinkInfo(i).callee.get())) {
+ if (verboseUnlinking)
+ dataLogF("Clearing call from %p to %p.\n", this, callLinkInfo(i).callee.get());
+ callLinkInfo(i).unlink(*m_globalData, repatchBuffer);
+ }
}
if (!!callLinkInfo(i).lastSeenCallee
&& !Heap::isMarked(callLinkInfo(i).lastSeenCallee.get()))
@@ -2238,7 +2303,7 @@ void CodeBlock::resetStubInternal(RepatchBuffer& repatchBuffer, StructureStubInf
AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
if (verboseUnlinking)
- dataLog("Clearing structure cache (kind %d) in %p.\n", stubInfo.accessType, this);
+ dataLogF("Clearing structure cache (kind %d) in %p.\n", stubInfo.accessType, this);
if (isGetByIdAccess(accessType)) {
if (getJITCode().jitType() == JITCode::DFGJIT)
@@ -2560,6 +2625,35 @@ Instruction* CodeBlock::adjustPCIfAtCallSite(Instruction* potentialReturnPC)
}
#endif // ENABLE(LLINT)
+#if ENABLE(JIT)
+ClosureCallStubRoutine* CodeBlock::findClosureCallForReturnPC(ReturnAddressPtr returnAddress)
+{
+ for (unsigned i = m_callLinkInfos.size(); i--;) {
+ CallLinkInfo& info = m_callLinkInfos[i];
+ if (!info.stub)
+ continue;
+ if (!info.stub->code().executableMemory()->contains(returnAddress.value()))
+ continue;
+
+ return info.stub.get();
+ }
+
+ // The stub routine may have been jettisoned. This is rare, but we have to handle it.
+ const JITStubRoutineSet& set = m_globalData->heap.jitStubRoutines();
+ for (unsigned i = set.size(); i--;) {
+ GCAwareJITStubRoutine* genericStub = set.at(i);
+ if (!genericStub->isClosureCall())
+ continue;
+ ClosureCallStubRoutine* stub = static_cast<ClosureCallStubRoutine*>(genericStub);
+ if (!stub->code().executableMemory()->contains(returnAddress.value()))
+ continue;
+ return stub;
+ }
+
+ return 0;
+}
+#endif
+
unsigned CodeBlock::bytecodeOffset(ExecState* exec, ReturnAddressPtr returnAddress)
{
UNUSED_PARAM(exec);
@@ -2597,7 +2691,16 @@ unsigned CodeBlock::bytecodeOffset(ExecState* exec, ReturnAddressPtr returnAddre
Vector<CallReturnOffsetToBytecodeOffset>& callIndices = m_rareData->m_callReturnIndexVector;
if (!callIndices.size())
return 1;
- return binarySearch<CallReturnOffsetToBytecodeOffset, unsigned, getCallReturnOffset>(callIndices.begin(), callIndices.size(), getJITCode().offsetOf(returnAddress.value()))->bytecodeOffset;
+
+ if (getJITCode().getExecutableMemory()->contains(returnAddress.value())) {
+ unsigned callReturnOffset = getJITCode().offsetOf(returnAddress.value());
+ CallReturnOffsetToBytecodeOffset* result =
+ binarySearch<CallReturnOffsetToBytecodeOffset, unsigned, getCallReturnOffset>(callIndices.begin(), callIndices.size(), callReturnOffset);
+ ASSERT(result->callReturnOffset == callReturnOffset);
+ return result->bytecodeOffset;
+ }
+
+ return findClosureCallForReturnPC(returnAddress)->codeOrigin().bytecodeIndex;
#endif // ENABLE(JIT)
#if !ENABLE(LLINT) && !ENABLE(JIT)
@@ -2605,6 +2708,26 @@ unsigned CodeBlock::bytecodeOffset(ExecState* exec, ReturnAddressPtr returnAddre
#endif
}
+#if ENABLE(DFG_JIT)
+bool CodeBlock::codeOriginForReturn(ReturnAddressPtr returnAddress, CodeOrigin& codeOrigin)
+{
+ if (!hasCodeOrigins())
+ return false;
+
+ if (!getJITCode().getExecutableMemory()->contains(returnAddress.value())) {
+ codeOrigin = findClosureCallForReturnPC(returnAddress)->codeOrigin();
+ return true;
+ }
+
+ unsigned offset = getJITCode().offsetOf(returnAddress.value());
+ CodeOriginAtCallReturnOffset* entry = binarySearch<CodeOriginAtCallReturnOffset, unsigned, getCallReturnOffsetForCodeOrigin>(codeOrigins().begin(), codeOrigins().size(), offset, WTF::KeyMustNotBePresentInArray);
+ if (entry->callReturnOffset != offset)
+ return false;
+ codeOrigin = entry->codeOrigin;
+ return true;
+}
+#endif // ENABLE(DFG_JIT)
+
void CodeBlock::clearEvalCache()
{
if (!!m_alternative)
@@ -2645,6 +2768,8 @@ void CodeBlock::reoptimize()
ASSERT(replacement() != this);
ASSERT(replacement()->alternative() == this);
replacement()->tallyFrequentExitSites();
+ if (DFG::shouldShowDisassembly())
+ dataLogF("DFG CodeBlock %p will be jettisoned due to reoptimization of %p.\n", replacement(), this);
replacement()->jettison();
countReoptimization();
optimizeAfterWarmUp();
@@ -2710,6 +2835,8 @@ void ProgramCodeBlock::jettison()
{
ASSERT(JITCode::isOptimizingJIT(getJITType()));
ASSERT(this == replacement());
+ if (DFG::shouldShowDisassembly())
+ dataLogF("Jettisoning DFG CodeBlock %p.\n", this);
static_cast<ProgramExecutable*>(ownerExecutable())->jettisonOptimizedCode(*globalData());
}
@@ -2717,6 +2844,8 @@ void EvalCodeBlock::jettison()
{
ASSERT(JITCode::isOptimizingJIT(getJITType()));
ASSERT(this == replacement());
+ if (DFG::shouldShowDisassembly())
+ dataLogF("Jettisoning DFG CodeBlock %p.\n", this);
static_cast<EvalExecutable*>(ownerExecutable())->jettisonOptimizedCode(*globalData());
}
@@ -2724,6 +2853,8 @@ void FunctionCodeBlock::jettison()
{
ASSERT(JITCode::isOptimizingJIT(getJITType()));
ASSERT(this == replacement());
+ if (DFG::shouldShowDisassembly())
+ dataLogF("Jettisoning DFG CodeBlock %p.\n", this);
static_cast<FunctionExecutable*>(ownerExecutable())->jettisonOptimizedCodeFor(*globalData(), m_isConstructor ? CodeForConstruct : CodeForCall);
}
@@ -2790,24 +2921,34 @@ 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()
{
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("Considering optimizing %p...\n", this);
+ dataLogF("Considering optimizing %p...\n", this);
#endif
#if ENABLE(VERBOSE_VALUE_PROFILE)
@@ -2817,12 +2958,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());
+ dataLogF("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())
@@ -2853,7 +2996,7 @@ void CodeBlock::tallyFrequentExitSites()
continue;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("OSR exit #%u (bc#%u, @%u, %s) for code block %p occurred frequently; counting as frequent exit site.\n", i, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, DFG::exitKindToString(exit.m_kind), this);
+ dataLogF("OSR exit #%u (bc#%u, @%u, %s) for code block %p occurred frequently; counting as frequent exit site.\n", i, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, DFG::exitKindToString(exit.m_kind), this);
#endif
}
}
@@ -2862,30 +3005,30 @@ void CodeBlock::tallyFrequentExitSites()
#if ENABLE(VERBOSE_VALUE_PROFILE)
void CodeBlock::dumpValueProfiles()
{
- dataLog("ValueProfile for %p:\n", this);
+ dataLogF("ValueProfile for %p:\n", this);
for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
ValueProfile* profile = getFromAllValueProfiles(i);
if (profile->m_bytecodeOffset < 0) {
ASSERT(profile->m_bytecodeOffset == -1);
- dataLog(" arg = %u: ", i);
+ dataLogF(" arg = %u: ", i);
} else
- dataLog(" bc = %d: ", profile->m_bytecodeOffset);
+ dataLogF(" bc = %d: ", profile->m_bytecodeOffset);
if (!profile->numberOfSamples() && profile->m_prediction == SpecNone) {
- dataLog("<empty>\n");
+ dataLogF("<empty>\n");
continue;
}
profile->dump(WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
}
- dataLog("RareCaseProfile for %p:\n", this);
+ dataLogF("RareCaseProfile for %p:\n", this);
for (unsigned i = 0; i < numberOfRareCaseProfiles(); ++i) {
RareCaseProfile* profile = rareCaseProfile(i);
- dataLog(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
+ dataLogF(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
}
- dataLog("SpecialFastCaseProfile for %p:\n", this);
+ dataLogF("SpecialFastCaseProfile for %p:\n", this);
for (unsigned i = 0; i < numberOfSpecialFastCaseProfiles(); ++i) {
RareCaseProfile* profile = specialFastCaseProfile(i);
- dataLog(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
+ dataLogF(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
}
}
#endif // ENABLE(VERBOSE_VALUE_PROFILE)
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index a28064940..63a03630e 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -163,7 +163,8 @@ namespace JSC {
static void dumpStatistics();
- void dump(ExecState*);
+ void dump();
+ void dump(unsigned bytecodeOffset);
void printStructures(const Instruction*);
void printStructure(const char* name, const Instruction*, int operand);
@@ -245,6 +246,7 @@ namespace JSC {
CallLinkInfo& getCallLinkInfo(unsigned bytecodeIndex)
{
+ ASSERT(JITCode::isBaselineCode(getJITType()));
return *(binarySearch<CallLinkInfo, unsigned, getCallLinkInfoBytecodeIndex>(m_callLinkInfos.begin(), m_callLinkInfos.size(), bytecodeIndex));
}
#endif // ENABLE(JIT)
@@ -274,6 +276,11 @@ namespace JSC {
{
m_incomingCalls.push(incoming);
}
+
+ bool isIncomingCallAlreadyLinked(CallLinkInfo* incoming)
+ {
+ return m_incomingCalls.isOnList(incoming);
+ }
#endif // ENABLE(JIT)
#if ENABLE(LLINT)
@@ -755,6 +762,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
@@ -806,17 +820,7 @@ namespace JSC {
return m_rareData && !!m_rareData->m_codeOrigins.size();
}
- bool codeOriginForReturn(ReturnAddressPtr returnAddress, CodeOrigin& codeOrigin)
- {
- if (!hasCodeOrigins())
- return false;
- unsigned offset = getJITCode().offsetOf(returnAddress.value());
- CodeOriginAtCallReturnOffset* entry = binarySearch<CodeOriginAtCallReturnOffset, unsigned, getCallReturnOffsetForCodeOrigin>(codeOrigins().begin(), codeOrigins().size(), offset, WTF::KeyMustNotBePresentInArray);
- if (entry->callReturnOffset != offset)
- return false;
- codeOrigin = entry->codeOrigin;
- return true;
- }
+ bool codeOriginForReturn(ReturnAddressPtr, CodeOrigin&);
CodeOrigin codeOrigin(unsigned index)
{
@@ -1145,9 +1149,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
@@ -1176,6 +1184,10 @@ namespace JSC {
private:
friend class DFGCodeBlocks;
+
+#if ENABLE(JIT)
+ ClosureCallStubRoutine* findClosureCallForReturnPC(ReturnAddressPtr);
+#endif
#if ENABLE(DFG_JIT)
void tallyFrequentExitSites();
@@ -1200,17 +1212,17 @@ namespace JSC {
m_constantRegisters[i].set(*m_globalData, ownerExecutable(), constants[i].get());
}
- void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&);
+ void dump(ExecState*, const Instruction* begin, const Instruction*&);
CString registerName(ExecState*, int r) const;
- void printUnaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op);
- void printBinaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op);
- void printConditionalJump(ExecState*, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator&, int location, const char* op);
- void printGetByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&);
+ void printUnaryOp(ExecState*, int location, const Instruction*&, const char* op);
+ void printBinaryOp(ExecState*, int location, const Instruction*&, const char* op);
+ void printConditionalJump(ExecState*, const Instruction*, const Instruction*&, int location, const char* op);
+ void printGetByIdOp(ExecState*, int location, const Instruction*&);
void printGetByIdCacheStatus(ExecState*, int location);
enum CacheDumpMode { DumpCaches, DontDumpCaches };
- void printCallOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op, CacheDumpMode);
- void printPutByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op);
+ void printCallOp(ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode);
+ void printPutByIdOp(ExecState*, int location, const Instruction*&, const char* op);
void visitStructures(SlotVisitor&, Instruction* vPC);
#if ENABLE(DFG_JIT)
@@ -1228,6 +1240,9 @@ namespace JSC {
// allow them to continue to execute soundly.
if (m_dfgData->mayBeExecuting)
return true;
+
+ if (Options::forceDFGCodeBlockLiveness())
+ return true;
return false;
}
@@ -1330,6 +1345,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/GetByIdStatus.cpp b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
index 605a81c2f..d17c17325 100644
--- a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
+++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
@@ -151,7 +151,7 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
// Finally figure out if we can derive an access strategy.
GetByIdStatus result;
- result.m_wasSeenInJIT = true;
+ result.m_wasSeenInJIT = true; // This is interesting for bytecode dumping only.
switch (stubInfo.accessType) {
case access_unset:
return computeFromLLInt(profiledBlock, bytecodeIndex, ident);
@@ -252,5 +252,35 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
#endif // ENABLE(JIT)
}
+GetByIdStatus GetByIdStatus::computeFor(JSGlobalData& globalData, Structure* structure, Identifier& ident)
+{
+ // For now we only handle the super simple self access case. We could handle the
+ // prototype case in the future.
+
+ if (PropertyName(ident).asIndex() != PropertyName::NotAnIndex)
+ return GetByIdStatus(TakesSlowPath);
+
+ if (structure->typeInfo().overridesGetOwnPropertySlot())
+ return GetByIdStatus(TakesSlowPath);
+
+ if (!structure->propertyAccessesAreCacheable())
+ return GetByIdStatus(TakesSlowPath);
+
+ GetByIdStatus result;
+ result.m_wasSeenInJIT = false; // To my knowledge nobody that uses computeFor(JSGlobalData&, Structure*, Identifier&) reads this field, but I might as well be honest: no, it wasn't seen in the JIT, since I computed it statically.
+ unsigned attributes;
+ JSCell* specificValue;
+ result.m_offset = structure->get(globalData, ident, attributes, specificValue);
+ if (!isValidOffset(result.m_offset))
+ return GetByIdStatus(TakesSlowPath); // It's probably a prototype lookup. Give up on life for now, even though we could totally be way smarter about it.
+ if (attributes & Accessor)
+ return GetByIdStatus(MakesCalls);
+ if (structure->isDictionary())
+ specificValue = 0;
+ result.m_structureSet.add(structure);
+ result.m_specificValue = JSValue(specificValue);
+ return result;
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.h b/Source/JavaScriptCore/bytecode/GetByIdStatus.h
index f38a19e8c..45d8c0b1f 100644
--- a/Source/JavaScriptCore/bytecode/GetByIdStatus.h
+++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.h
@@ -51,6 +51,13 @@ public:
{
}
+ explicit GetByIdStatus(State state)
+ : m_state(state)
+ , m_offset(invalidOffset)
+ {
+ ASSERT(state == NoInformation || state == TakesSlowPath || state == MakesCalls);
+ }
+
GetByIdStatus(
State state, bool wasSeenInJIT, const StructureSet& structureSet = StructureSet(),
PropertyOffset offset = invalidOffset, JSValue specificValue = JSValue(), Vector<Structure*> chain = Vector<Structure*>())
@@ -65,6 +72,7 @@ public:
}
static GetByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&);
+ static GetByIdStatus computeFor(JSGlobalData&, Structure*, Identifier&);
State state() const { return m_state; }
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.cpp b/Source/JavaScriptCore/bytecode/Opcode.cpp
index a27714026..0adc76b28 100644
--- a/Source/JavaScriptCore/bytecode/Opcode.cpp
+++ b/Source/JavaScriptCore/bytecode/Opcode.cpp
@@ -114,19 +114,19 @@ OpcodeStats::~OpcodeStats()
*(currentPairIndex++) = make_pair(i, j);
qsort(sortedPairIndices, numOpcodeIDs * numOpcodeIDs, sizeof(pair<int, int>), compareOpcodePairIndices);
- dataLog("\nExecuted opcode statistics\n");
+ dataLogF("\nExecuted opcode statistics\n");
- dataLog("Total instructions executed: %lld\n\n", totalInstructions);
+ dataLogF("Total instructions executed: %lld\n\n", totalInstructions);
- dataLog("All opcodes by frequency:\n\n");
+ dataLogF("All opcodes by frequency:\n\n");
for (int i = 0; i < numOpcodeIDs; ++i) {
int index = sortedIndices[i];
- dataLog("%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCounts[index], ((double) opcodeCounts[index]) / ((double) totalInstructions) * 100.0);
+ dataLogF("%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCounts[index], ((double) opcodeCounts[index]) / ((double) totalInstructions) * 100.0);
}
- dataLog("\n");
- dataLog("2-opcode sequences by frequency: %lld\n\n", totalInstructions);
+ dataLogF("\n");
+ dataLogF("2-opcode sequences by frequency: %lld\n\n", totalInstructions);
for (int i = 0; i < numOpcodeIDs * numOpcodeIDs; ++i) {
pair<int, int> indexPair = sortedPairIndices[i];
@@ -135,11 +135,11 @@ OpcodeStats::~OpcodeStats()
if (!count)
break;
- dataLog("%s%s %s:%s %lld %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), count, ((double) count) / ((double) totalInstructionPairs) * 100.0);
+ dataLogF("%s%s %s:%s %lld %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), count, ((double) count) / ((double) totalInstructionPairs) * 100.0);
}
- dataLog("\n");
- dataLog("Most common opcodes and sequences:\n");
+ dataLogF("\n");
+ dataLogF("Most common opcodes and sequences:\n");
for (int i = 0; i < numOpcodeIDs; ++i) {
int index = sortedIndices[i];
@@ -147,7 +147,7 @@ OpcodeStats::~OpcodeStats()
double opcodeProportion = ((double) opcodeCount) / ((double) totalInstructions);
if (opcodeProportion < 0.0001)
break;
- dataLog("\n%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCount, opcodeProportion * 100.0);
+ dataLogF("\n%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCount, opcodeProportion * 100.0);
for (int j = 0; j < numOpcodeIDs * numOpcodeIDs; ++j) {
pair<int, int> indexPair = sortedPairIndices[j];
@@ -160,11 +160,11 @@ OpcodeStats::~OpcodeStats()
if (indexPair.first != index && indexPair.second != index)
continue;
- dataLog(" %s%s %s:%s %lld - %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), pairCount, pairProportion * 100.0);
+ dataLogF(" %s%s %s:%s %lld - %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), pairCount, pairProportion * 100.0);
}
}
- dataLog("\n");
+ dataLogF("\n");
}
void OpcodeStats::recordInstruction(int opcode)
diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h
index 8979d0b7b..5fe28bc09 100644
--- a/Source/JavaScriptCore/bytecode/Opcode.h
+++ b/Source/JavaScriptCore/bytecode/Opcode.h
@@ -44,13 +44,14 @@ namespace JSC {
macro(op_create_activation, 2) \
macro(op_init_lazy_reg, 2) \
macro(op_create_arguments, 2) \
- macro(op_create_this, 2) \
+ macro(op_create_this, 3) \
+ macro(op_get_callee, 3) \
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/Operands.h b/Source/JavaScriptCore/bytecode/Operands.h
index b0f0e692c..0cea096cf 100644
--- a/Source/JavaScriptCore/bytecode/Operands.h
+++ b/Source/JavaScriptCore/bytecode/Operands.h
@@ -190,7 +190,7 @@ private:
};
template<typename T, typename Traits>
-void dumpOperands(Operands<T, Traits>& operands, FILE* out)
+void dumpOperands(const Operands<T, Traits>& operands, FILE* out)
{
for (size_t argument = 0; argument < operands.numberOfArguments(); ++argument) {
if (argument)
@@ -205,16 +205,6 @@ void dumpOperands(Operands<T, Traits>& operands, FILE* out)
}
}
-template<typename T, typename Traits>
-void dumpOperands(const Operands<T, Traits>& operands, FILE* out)
-{
- // Use const-cast because:
- // 1) I don't feel like writing this code twice, and
- // 2) Some dump() methods may not be const, and I don't really care if that's
- // the case.
- dumpOperands(*const_cast<Operands<T, Traits>*>(&operands), out);
-}
-
} // namespace JSC
#endif // Operands_h
diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
index 35800f3dd..7d6ba0987 100644
--- a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
+++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
@@ -29,6 +29,7 @@
#include "CodeBlock.h"
#include "LLIntData.h"
#include "LowLevelInterpreter.h"
+#include "Operations.h"
#include "Structure.h"
#include "StructureChain.h"
@@ -134,5 +135,77 @@ PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
#endif // ENABLE(JIT)
}
+PutByIdStatus PutByIdStatus::computeFor(JSGlobalData& globalData, JSGlobalObject* globalObject, Structure* structure, Identifier& ident, bool isDirect)
+{
+ if (PropertyName(ident).asIndex() != PropertyName::NotAnIndex)
+ return PutByIdStatus(TakesSlowPath);
+
+ if (structure->typeInfo().overridesGetOwnPropertySlot())
+ return PutByIdStatus(TakesSlowPath);
+
+ if (!structure->propertyAccessesAreCacheable())
+ return PutByIdStatus(TakesSlowPath);
+
+ unsigned attributes;
+ JSCell* specificValueIgnored;
+ PropertyOffset offset = structure->get(globalData, ident, attributes, specificValueIgnored);
+ if (isValidOffset(offset)) {
+ if (attributes & (Accessor | ReadOnly))
+ return PutByIdStatus(TakesSlowPath);
+ return PutByIdStatus(SimpleReplace, structure, 0, 0, offset);
+ }
+
+ // Our hypothesis is that we're doing a transition. Before we prove that this is really
+ // true, we want to do some sanity checks.
+
+ // Don't cache put transitions on dictionaries.
+ if (structure->isDictionary())
+ return PutByIdStatus(TakesSlowPath);
+
+ // If the structure corresponds to something that isn't an object, then give up, since
+ // we don't want to be adding properties to strings.
+ if (structure->typeInfo().type() == StringType)
+ return PutByIdStatus(TakesSlowPath);
+
+ if (!isDirect) {
+ // If the prototype chain has setters or read-only properties, then give up.
+ if (structure->prototypeChainMayInterceptStoreTo(globalData, ident))
+ return PutByIdStatus(TakesSlowPath);
+
+ // If the prototype chain hasn't been normalized (i.e. there are proxies or dictionaries)
+ // then give up. The dictionary case would only happen if this structure has not been
+ // used in an optimized put_by_id transition. And really the only reason why we would
+ // bail here is that I don't really feel like having the optimizing JIT go and flatten
+ // dictionaries if we have evidence to suggest that those objects were never used as
+ // prototypes in a cacheable prototype access - i.e. there's a good chance that some of
+ // the other checks below will fail.
+ if (!isPrototypeChainNormalized(globalObject, structure))
+ return PutByIdStatus(TakesSlowPath);
+ }
+
+ // We only optimize if there is already a structure that the transition is cached to.
+ // Among other things, this allows us to guard against a transition with a specific
+ // value.
+ //
+ // - If we're storing a value that could be specific: this would only be a problem if
+ // the existing transition did have a specific value already, since if it didn't,
+ // then we would behave "as if" we were not storing a specific value. If it did
+ // have a specific value, then we'll know - the fact that we pass 0 for
+ // specificValue will tell us.
+ //
+ // - If we're not storing a value that could be specific: again, this would only be a
+ // problem if the existing transition did have a specific value, which we check for
+ // by passing 0 for the specificValue.
+ Structure* transition = Structure::addPropertyTransitionToExistingStructure(structure, ident, 0, 0, offset);
+ if (!transition)
+ return PutByIdStatus(TakesSlowPath); // This occurs in bizarre cases only. See above.
+ ASSERT(!transition->transitionDidInvolveSpecificValue());
+ ASSERT(isValidOffset(offset));
+
+ return PutByIdStatus(
+ SimpleTransition, structure, transition,
+ structure->prototypeChain(globalData, globalObject), offset);
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.h b/Source/JavaScriptCore/bytecode/PutByIdStatus.h
index 694915244..fe22009fe 100644
--- a/Source/JavaScriptCore/bytecode/PutByIdStatus.h
+++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.h
@@ -33,6 +33,8 @@ namespace JSC {
class CodeBlock;
class Identifier;
+class JSGlobalData;
+class JSGlobalObject;
class Structure;
class StructureChain;
@@ -60,6 +62,16 @@ public:
{
}
+ explicit PutByIdStatus(State state)
+ : m_state(state)
+ , m_oldStructure(0)
+ , m_newStructure(0)
+ , m_structureChain(0)
+ , m_offset(invalidOffset)
+ {
+ ASSERT(m_state == NoInformation || m_state == TakesSlowPath);
+ }
+
PutByIdStatus(
State state,
Structure* oldStructure,
@@ -79,6 +91,7 @@ public:
}
static PutByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&);
+ static PutByIdStatus computeFor(JSGlobalData&, JSGlobalObject*, Structure*, Identifier&, bool isDirect);
State state() const { return m_state; }
diff --git a/Source/JavaScriptCore/bytecode/SamplingTool.cpp b/Source/JavaScriptCore/bytecode/SamplingTool.cpp
index f9b8245e5..a76fee179 100644
--- a/Source/JavaScriptCore/bytecode/SamplingTool.cpp
+++ b/Source/JavaScriptCore/bytecode/SamplingTool.cpp
@@ -67,14 +67,14 @@ void SamplingFlags::stop()
total += s_flagCounts[i];
if (total) {
- dataLog("\nSamplingFlags: sample counts with flags set: (%lld total)\n", total);
+ dataLogF("\nSamplingFlags: sample counts with flags set: (%lld total)\n", total);
for (unsigned i = 0; i <= 32; ++i) {
if (s_flagCounts[i])
- dataLog(" [ %02d ] : %lld\t\t(%03.2f%%)\n", i, s_flagCounts[i], (100.0 * s_flagCounts[i]) / total);
+ dataLogF(" [ %02d ] : %lld\t\t(%03.2f%%)\n", i, s_flagCounts[i], (100.0 * s_flagCounts[i]) / total);
}
- dataLog("\n");
+ dataLogF("\n");
} else
- dataLog("\nSamplingFlags: no samples.\n\n");
+ dataLogF("\nSamplingFlags: no samples.\n\n");
}
uint64_t SamplingFlags::s_flagCounts[33];
@@ -151,7 +151,7 @@ void SamplingRegion::dump()
void SamplingRegion::dumpInternal()
{
if (!s_spectrum) {
- dataLog("\nSamplingRegion: was never sampled.\n\n");
+ dataLogF("\nSamplingRegion: was never sampled.\n\n");
return;
}
@@ -161,10 +161,10 @@ void SamplingRegion::dumpInternal()
for (unsigned i = list.size(); i--;)
total += list[i].count;
- dataLog("\nSamplingRegion: sample counts for regions: (%lu samples)\n", total);
+ dataLogF("\nSamplingRegion: sample counts for regions: (%lu samples)\n", total);
for (unsigned i = list.size(); i--;)
- dataLog(" %3.2lf%% %s\n", (100.0 * list[i].count) / total, list[i].key);
+ dataLogF(" %3.2lf%% %s\n", (100.0 * list[i].count) / total, list[i].key);
}
#else // ENABLE(SAMPLING_REGIONS)
void SamplingRegion::dump() { }
@@ -371,10 +371,10 @@ void SamplingTool::dump(ExecState* exec)
// (2) Print Opcode sampling results.
- dataLog("\nBytecode samples [*]\n");
- dataLog(" sample %% of %% of | cti cti %%\n");
- dataLog("opcode count VM total | count of self\n");
- dataLog("------------------------------------------------------- | ----------------\n");
+ dataLogF("\nBytecode samples [*]\n");
+ dataLogF(" sample %% of %% of | cti cti %%\n");
+ dataLogF("opcode count VM total | count of self\n");
+ dataLogF("------------------------------------------------------- | ----------------\n");
for (int i = 0; i < numOpcodeIDs; ++i) {
long long count = opcodeSampleInfo[i].count;
@@ -392,15 +392,15 @@ void SamplingTool::dump(ExecState* exec)
debugDebugPrintf("%s:%s%-6lld %.3f%%\t%.3f%%\t | %-6lld %.3f%%\n", opcodeName, opcodePadding, count, percentOfVM, percentOfTotal, countInCTIFunctions, percentInCTIFunctions);
}
- dataLog("\n[*] Samples inside host code are not charged to any Bytecode.\n\n");
- dataLog("\tSamples inside VM:\t\t%lld / %lld (%.3f%%)\n", m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_opcodeSampleCount) * 100) / m_sampleCount);
- dataLog("\tSamples inside host code:\t%lld / %lld (%.3f%%)\n\n", m_sampleCount - m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_sampleCount - m_opcodeSampleCount) * 100) / m_sampleCount);
- dataLog("\tsample count:\tsamples inside this opcode\n");
- dataLog("\t%% of VM:\tsample count / all opcode samples\n");
- dataLog("\t%% of total:\tsample count / all samples\n");
- dataLog("\t--------------\n");
- dataLog("\tcti count:\tsamples inside a CTI function called by this opcode\n");
- dataLog("\tcti %% of self:\tcti count / sample count\n");
+ dataLogF("\n[*] Samples inside host code are not charged to any Bytecode.\n\n");
+ dataLogF("\tSamples inside VM:\t\t%lld / %lld (%.3f%%)\n", m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_opcodeSampleCount) * 100) / m_sampleCount);
+ dataLogF("\tSamples inside host code:\t%lld / %lld (%.3f%%)\n\n", m_sampleCount - m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_sampleCount - m_opcodeSampleCount) * 100) / m_sampleCount);
+ dataLogF("\tsample count:\tsamples inside this opcode\n");
+ dataLogF("\t%% of VM:\tsample count / all opcode samples\n");
+ dataLogF("\t%% of total:\tsample count / all samples\n");
+ dataLogF("\t--------------\n");
+ dataLogF("\tcti count:\tsamples inside a CTI function called by this opcode\n");
+ dataLogF("\tcti %% of self:\tcti count / sample count\n");
#if ENABLE(CODEBLOCK_SAMPLING)
@@ -416,7 +416,7 @@ void SamplingTool::dump(ExecState* exec)
// (4) Print data from 'codeBlockSamples' array.
- dataLog("\nCodeBlock samples\n\n");
+ dataLogF("\nCodeBlock samples\n\n");
for (int i = 0; i < scopeCount; ++i) {
ScriptSampleRecord* record = codeBlockSamples[i];
@@ -426,21 +426,21 @@ void SamplingTool::dump(ExecState* exec)
if (blockPercent >= 1) {
//Instruction* code = codeBlock->instructions().begin();
- dataLog("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_executable->sourceURL().utf8().data(), codeBlock->lineNumberForBytecodeOffset(0), record->m_sampleCount, m_sampleCount, blockPercent);
+ dataLogF("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_executable->sourceURL().utf8().data(), codeBlock->lineNumberForBytecodeOffset(0), record->m_sampleCount, m_sampleCount, blockPercent);
if (i < 10) {
HashMap<unsigned,unsigned> lineCounts;
codeBlock->dump(exec);
- dataLog(" Opcode and line number samples [*]\n\n");
+ dataLogF(" Opcode and line number samples [*]\n\n");
for (unsigned op = 0; op < record->m_size; ++op) {
int count = record->m_samples[op];
if (count) {
- dataLog(" [% 4d] has sample count: % 4d\n", op, count);
+ dataLogF(" [% 4d] has sample count: % 4d\n", op, count);
unsigned line = codeBlock->lineNumberForBytecodeOffset(op);
lineCounts.set(line, (lineCounts.contains(line) ? lineCounts.get(line) : 0) + count);
}
}
- dataLog("\n");
+ dataLogF("\n");
int linesCount = lineCounts.size();
Vector<LineCountInfo> lineCountInfo(linesCount);
@@ -453,12 +453,12 @@ void SamplingTool::dump(ExecState* exec)
qsort(lineCountInfo.begin(), linesCount, sizeof(LineCountInfo), compareLineCountInfoSampling);
for (lineno = 0; lineno < linesCount; ++lineno) {
- dataLog(" Line #%d has sample count %d.\n", lineCountInfo[lineno].line, lineCountInfo[lineno].count);
+ dataLogF(" Line #%d has sample count %d.\n", lineCountInfo[lineno].line, lineCountInfo[lineno].count);
}
- dataLog("\n");
- dataLog(" [*] Samples inside host code are charged to the calling Bytecode.\n");
- dataLog(" Samples on a call / return boundary are not charged to a specific opcode or line.\n\n");
- dataLog(" Samples on a call / return boundary: %d / %d (%.3f%%)\n\n", record->m_sampleCount - record->m_opcodeSampleCount, record->m_sampleCount, (static_cast<double>(record->m_sampleCount - record->m_opcodeSampleCount) * 100) / record->m_sampleCount);
+ dataLogF("\n");
+ dataLogF(" [*] Samples inside host code are charged to the calling Bytecode.\n");
+ dataLogF(" Samples on a call / return boundary are not charged to a specific opcode or line.\n\n");
+ dataLogF(" Samples on a call / return boundary: %d / %d (%.3f%%)\n\n", record->m_sampleCount - record->m_opcodeSampleCount, record->m_sampleCount, (static_cast<double>(record->m_sampleCount - record->m_opcodeSampleCount) * 100) / record->m_sampleCount);
}
}
}
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/StructureStubInfo.h b/Source/JavaScriptCore/bytecode/StructureStubInfo.h
index a1bbc9c37..445ffe6c6 100644
--- a/Source/JavaScriptCore/bytecode/StructureStubInfo.h
+++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.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
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..c6f81f3c3 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -457,8 +457,16 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode*
if (isConstructor()) {
prependComment("'this' because we are a Constructor function");
- emitOpcode(op_create_this);
- instructions().append(m_thisRegister.index());
+
+ RefPtr<RegisterID> func = newTemporary();
+
+ UnlinkedValueProfile profile = emitProfiledOpcode(op_get_callee);
+ instructions().append(func->index());
+ instructions().append(profile);
+
+ emitOpcode(op_create_this);
+ instructions().append(m_thisRegister.index());
+ instructions().append(func->index());
} else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) {
UnlinkedValueProfile profile = emitProfiledOpcode(op_convert_this);
instructions().append(m_thisRegister.index());
@@ -716,6 +724,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 +1622,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 +1640,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 +1776,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/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 85da1f4eb..71b6c7cac 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -1035,6 +1035,16 @@ RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator));
RegisterID* src2 = generator.emitNode(m_expr2);
+ if (generator.m_lastOpcodeID == op_typeof && (opcodeID == op_neq || opcodeID == op_nstricteq)) {
+ RefPtr<RegisterID> tmp = generator.tempDestination(dst);
+ if (opcodeID == op_neq)
+ generator.emitEqualityOp(op_eq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2);
+ else if (opcodeID == op_nstricteq)
+ generator.emitEqualityOp(op_stricteq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2);
+ else
+ ASSERT_NOT_REACHED();
+ return generator.emitUnaryOp(op_not, generator.finalDestination(dst, tmp.get()), tmp.get());
+ }
return generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor()));
}
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..23b84cedf 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -30,6 +30,8 @@
#include "CodeBlock.h"
#include "DFGBasicBlock.h"
+#include "GetByIdStatus.h"
+#include "PutByIdStatus.h"
namespace JSC { namespace DFG {
@@ -150,16 +152,16 @@ void AbstractState::initialize(Graph& graph)
int operand = graph.m_mustHandleValues.operandForIndex(i);
block->valuesAtHead.operand(operand).merge(value);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Initializing Block #%u, operand r%d, to ", blockIndex, operand);
+ dataLogF(" Initializing Block #%u, operand r%d, to ", blockIndex, operand);
block->valuesAtHead.operand(operand).dump(WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
#endif
}
block->cfaShouldRevisit = true;
}
}
-bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDirectionPtr)
+bool AbstractState::endBasicBlock(MergeMode mergeMode)
{
ASSERT(m_block);
@@ -167,6 +169,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi
block->cfaFoundConstants = m_foundConstants;
block->cfaDidFinish = m_isValid;
+ block->cfaBranchDirection = m_branchDirection;
if (!m_isValid) {
reset();
@@ -178,7 +181,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi
if (mergeMode != DontMerge || !ASSERT_DISABLED) {
for (size_t argument = 0; argument < block->variablesAtTail.numberOfArguments(); ++argument) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Merging state for argument %zu.\n", argument);
+ dataLogF(" Merging state for argument %zu.\n", argument);
#endif
AbstractValue& destination = block->valuesAtTail.argument(argument);
changed |= mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
@@ -186,7 +189,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi
for (size_t local = 0; local < block->variablesAtTail.numberOfLocals(); ++local) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Merging state for local %zu.\n", local);
+ dataLogF(" Merging state for local %zu.\n", local);
#endif
AbstractValue& destination = block->valuesAtTail.local(local);
changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
@@ -195,12 +198,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));
+ dataLogF(" Branch direction = %s\n", branchDirectionToString(m_branchDirection));
#endif
reset();
@@ -208,7 +207,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()
@@ -218,6 +217,27 @@ void AbstractState::reset()
m_branchDirection = InvalidBranchDirection;
}
+AbstractState::BooleanResult AbstractState::booleanResult(Node& node, AbstractValue& value)
+{
+ JSValue childConst = value.value();
+ if (childConst) {
+ if (childConst.toBoolean(m_codeBlock->globalObjectFor(node.codeOrigin)->globalExec()))
+ return DefinitelyTrue;
+ return DefinitelyFalse;
+ }
+
+ // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
+ if (isCellSpeculation(value.m_type)
+ && value.m_currentKnownStructure.hasSingleton()) {
+ Structure* structure = value.m_currentKnownStructure.singleton();
+ if (!structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node.codeOrigin))
+ && structure->typeInfo().type() != StringType)
+ return DefinitelyTrue;
+ }
+
+ return UnknownBooleanResult;
+}
+
bool AbstractState::execute(unsigned indexInBlock)
{
ASSERT(m_block);
@@ -239,6 +259,12 @@ bool AbstractState::execute(unsigned indexInBlock)
node.setCanExit(false);
break;
}
+
+ case Identity: {
+ forNode(nodeIndex) = forNode(node.child1());
+ node.setCanExit(false);
+ break;
+ }
case GetLocal: {
VariableAccessData* variableAccessData = node.variableAccessData();
@@ -424,7 +450,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 +477,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 +555,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 +597,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 +617,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,8 +642,18 @@ bool AbstractState::execute(unsigned indexInBlock)
}
case LogicalNot: {
- JSValue childConst = forNode(node.child1()).value();
- if (childConst && trySetConstant(nodeIndex, jsBoolean(!childConst.toBoolean(m_codeBlock->globalObjectFor(node.codeOrigin)->globalExec())))) {
+ bool didSetConstant = false;
+ switch (booleanResult(node, forNode(node.child1()))) {
+ case DefinitelyTrue:
+ didSetConstant = trySetConstant(nodeIndex, jsBoolean(false));
+ break;
+ case DefinitelyFalse:
+ didSetConstant = trySetConstant(nodeIndex, jsBoolean(true));
+ break;
+ default:
+ break;
+ }
+ if (didSetConstant) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -678,12 +725,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 +753,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 +899,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 +917,24 @@ 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 if (node.arrayMode().isSaneChain())
+ forNode(nodeIndex).set(SpecDouble);
+ else
+ forNode(nodeIndex).set(SpecDoubleReal);
+ break;
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
@@ -926,6 +1002,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 +1108,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,23 +1143,21 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
case Branch: {
- JSValue value = forNode(node.child1()).value();
- if (value) {
- bool booleanValue = value.toBoolean(m_codeBlock->globalObjectFor(node.codeOrigin)->globalExec());
- if (booleanValue)
- m_branchDirection = TakeTrue;
- else
- m_branchDirection = TakeFalse;
+ BooleanResult result = booleanResult(node, forNode(node.child1()));
+ if (result == DefinitelyTrue) {
+ m_branchDirection = TakeTrue;
+ node.setCanExit(false);
+ break;
+ }
+ if (result == DefinitelyFalse) {
+ m_branchDirection = TakeFalse;
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
- // something that is known to evaluate true (or false) then we ought
- // to sparse conditional that.
- // 2) We can specialize the source variable's value on each direction of
- // the branch.
+ // We can specialize the source variable's value on each direction of
+ // the branch.
Node& child = m_graph[node.child1()];
if (child.shouldSpeculateBoolean())
speculateBooleanUnary(node);
@@ -1122,13 +1220,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;
@@ -1156,6 +1254,7 @@ bool AbstractState::execute(unsigned indexInBlock)
// be hit, but then again, you never know.
destination = source;
node.setCanExit(false);
+ m_foundConstants = true; // Tell the constant folder to turn this into Identity.
break;
}
@@ -1188,10 +1287,14 @@ bool AbstractState::execute(unsigned indexInBlock)
destination.set(SpecFinalObject);
break;
}
+
+ case InheritorIDWatchpoint:
+ node.setCanExit(true);
+ break;
case NewObject:
node.setCanExit(false);
- forNode(nodeIndex).set(m_codeBlock->globalObjectFor(node.codeOrigin)->emptyObjectStructure());
+ forNode(nodeIndex).set(node.structure());
m_haveStructures = true;
break;
@@ -1308,8 +1411,30 @@ bool AbstractState::execute(unsigned indexInBlock)
m_isValid = false;
break;
}
- if (isCellSpeculation(m_graph[node.child1()].prediction()))
+ if (isCellSpeculation(m_graph[node.child1()].prediction())) {
forNode(node.child1()).filter(SpecCell);
+
+ if (Structure* structure = forNode(node.child1()).bestProvenStructure()) {
+ GetByIdStatus status = GetByIdStatus::computeFor(
+ m_graph.m_globalData, structure,
+ m_graph.m_codeBlock->identifier(node.identifierNumber()));
+ if (status.isSimple()) {
+ // Assert things that we can't handle and that the computeFor() method
+ // above won't be able to return.
+ ASSERT(status.structureSet().size() == 1);
+ ASSERT(status.chain().isEmpty());
+
+ if (status.specificValue())
+ forNode(nodeIndex).set(status.specificValue());
+ else
+ forNode(nodeIndex).makeTop();
+ forNode(node.child1()).filter(status.structureSet());
+
+ m_foundConstants = true;
+ break;
+ }
+ }
+ }
clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
@@ -1374,7 +1499,7 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(nodeIndex).clear(); // The result is not a JS value.
break;
case CheckArray: {
- if (node.arrayMode().alreadyChecked(forNode(node.child1()))) {
+ if (node.arrayMode().alreadyChecked(m_graph, node, forNode(node.child1()))) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -1384,11 +1509,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:
@@ -1430,7 +1555,7 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
}
case Arrayify: {
- if (node.arrayMode().alreadyChecked(forNode(node.child1()))) {
+ if (node.arrayMode().alreadyChecked(m_graph, node, forNode(node.child1()))) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -1472,25 +1597,65 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
}
case GetByOffset:
- node.setCanExit(!isCellSpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecCell);
+ if (!m_graph[node.child1()].hasStorageResult()) {
+ node.setCanExit(!isCellSpeculation(forNode(node.child1()).m_type));
+ forNode(node.child1()).filter(SpecCell);
+ }
forNode(nodeIndex).makeTop();
break;
- case PutByOffset:
- node.setCanExit(!isCellSpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecCell);
+ case PutByOffset: {
+ bool canExit = false;
+ if (!m_graph[node.child1()].hasStorageResult()) {
+ canExit |= !isCellSpeculation(forNode(node.child1()).m_type);
+ forNode(node.child1()).filter(SpecCell);
+ }
+ canExit |= !isCellSpeculation(forNode(node.child2()).m_type);
+ forNode(node.child2()).filter(SpecCell);
+ node.setCanExit(canExit);
break;
+ }
- case CheckFunction:
+ case CheckFunction: {
+ JSValue value = forNode(node.child1()).value();
+ if (value == node.function()) {
+ m_foundConstants = true;
+ ASSERT(value);
+ node.setCanExit(false);
+ break;
+ }
+
node.setCanExit(true); // Lies! We can do better.
- forNode(node.child1()).filter(SpecFunction);
- // FIXME: Should be able to propagate the fact that we know what the function is.
+ if (!forNode(node.child1()).filterByValue(node.function())) {
+ m_isValid = false;
+ break;
+ }
break;
+ }
case PutById:
case PutByIdDirect:
node.setCanExit(true);
+ if (Structure* structure = forNode(node.child1()).bestProvenStructure()) {
+ PutByIdStatus status = PutByIdStatus::computeFor(
+ m_graph.m_globalData,
+ m_graph.globalObjectFor(node.codeOrigin),
+ structure,
+ m_graph.m_codeBlock->identifier(node.identifierNumber()),
+ node.op() == PutByIdDirect);
+ if (status.isSimpleReplace()) {
+ forNode(node.child1()).filter(structure);
+ m_foundConstants = true;
+ break;
+ }
+ if (status.isSimpleTransition()) {
+ clobberStructures(indexInBlock);
+ forNode(node.child1()).set(status.newStructure());
+ m_haveStructures = true;
+ m_foundConstants = true;
+ break;
+ }
+ }
forNode(node.child1()).filter(SpecCell);
clobberWorld(node.codeOrigin, indexInBlock);
break;
@@ -1622,15 +1787,15 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
return false;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" It's live, node @%u.\n", nodeIndex);
+ dataLogF(" It's live, node @%u.\n", nodeIndex);
#endif
if (node.variableAccessData()->isCaptured()) {
source = inVariable;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Transfering ");
+ dataLogF(" Transfering ");
source.dump(WTF::dataFile());
- dataLog(" from last access due to captured variable.\n");
+ dataLogF(" from last access due to captured variable.\n");
#endif
} else {
switch (node.op()) {
@@ -1640,9 +1805,9 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
// The block transfers the value from head to tail.
source = inVariable;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Transfering ");
+ dataLogF(" Transfering ");
source.dump(WTF::dataFile());
- dataLog(" from head to tail.\n");
+ dataLogF(" from head to tail.\n");
#endif
break;
@@ -1650,9 +1815,9 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
// The block refines the value with additional speculations.
source = forNode(nodeIndex);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Refining to ");
+ dataLogF(" Refining to ");
source.dump(WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
#endif
break;
@@ -1665,9 +1830,9 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
} else
source = forNode(node.child1());
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Setting to ");
+ dataLogF(" Setting to ");
source.dump(WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
#endif
break;
@@ -1681,7 +1846,7 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
// Abstract execution did not change the output value of the variable, for this
// basic block, on this iteration.
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Not changed!\n");
+ dataLogF(" Not changed!\n");
#endif
return false;
}
@@ -1691,7 +1856,7 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
// true to indicate that the fixpoint must go on!
destination = source;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Changed!\n");
+ dataLogF(" Changed!\n");
#endif
return true;
}
@@ -1722,7 +1887,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,25 +1895,25 @@ 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());
+ dataLogF(" Merging to block #%u.\n", terminal.takenBlockIndex());
#endif
return merge(basicBlock, graph.m_blocks[terminal.takenBlockIndex()].get());
}
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());
+ dataLogF(" 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());
+ dataLogF(" 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 +1921,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..230cd836c 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:
@@ -268,6 +235,13 @@ private:
childValue2.filter(SpecNumber);
}
+ enum BooleanResult {
+ UnknownBooleanResult,
+ DefinitelyFalse,
+ DefinitelyTrue
+ };
+ BooleanResult booleanResult(Node&, AbstractValue&);
+
bool trySetConstant(NodeIndex nodeIndex, JSValue value)
{
// Make sure we don't constant fold something that will produce values that contravene
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
index c198b5e52..c60b792f6 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
@@ -284,6 +284,21 @@ struct AbstractValue {
checkConsistency();
}
+ bool filterByValue(JSValue value)
+ {
+ if (!validate(value))
+ return false;
+
+ if (!!value && value.isCell())
+ filter(StructureSet(value.asCell()->structure()));
+ else
+ filter(speculationFromValue(value));
+
+ m_value = value;
+
+ return true;
+ }
+
bool validateType(JSValue value) const
{
if (isTop())
@@ -327,6 +342,15 @@ struct AbstractValue {
return true;
}
+ Structure* bestProvenStructure() const
+ {
+ if (m_currentKnownStructure.hasSingleton())
+ return m_currentKnownStructure.singleton();
+ if (m_futurePossibleStructure.hasSingleton())
+ return m_futurePossibleStructure.singleton();
+ return 0;
+ }
+
void checkConsistency() const
{
if (!(m_type & SpecCell)) {
@@ -351,7 +375,7 @@ struct AbstractValue {
{
fprintf(out, "(%s, %s, ", speculationToString(m_type), arrayModesToString(m_arrayModes));
m_currentKnownStructure.dump(out);
- dataLog(", ");
+ dataLogF(", ");
m_futurePossibleStructure.dump(out);
if (!!m_value)
fprintf(out, ", %s", m_value.description());
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
index 00b1109f6..b02e0112c 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
@@ -359,49 +359,49 @@ public:
}
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Arguments aliasing states:\n");
+ dataLogF("Arguments aliasing states:\n");
for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
if (!variableAccessData->isRoot())
continue;
- dataLog(" r%d(%s): ", variableAccessData->local(), m_graph.nameOfVariableAccessData(variableAccessData));
+ dataLogF(" r%d(%s): ", variableAccessData->local(), m_graph.nameOfVariableAccessData(variableAccessData));
if (variableAccessData->isCaptured())
- dataLog("Captured");
+ dataLogF("Captured");
else {
ArgumentsAliasingData& data =
m_argumentsAliasing.find(variableAccessData)->value;
bool first = true;
if (data.callContextIsValid()) {
if (!first)
- dataLog(", ");
- dataLog("Have Call Context: %p", data.callContext);
+ dataLogF(", ");
+ dataLogF("Have Call Context: %p", data.callContext);
first = false;
if (!m_createsArguments.contains(data.callContext))
- dataLog(" (Does Not Create Arguments)");
+ dataLogF(" (Does Not Create Arguments)");
}
if (data.argumentsAssignmentIsValid()) {
if (!first)
- dataLog(", ");
- dataLog("Arguments Assignment Is Valid");
+ dataLogF(", ");
+ dataLogF("Arguments Assignment Is Valid");
first = false;
}
if (!data.escapes) {
if (!first)
- dataLog(", ");
- dataLog("Does Not Escape");
+ dataLogF(", ");
+ dataLogF("Does Not Escape");
first = false;
}
if (!first)
- dataLog(", ");
+ dataLogF(", ");
if (data.isValid()) {
if (m_createsArguments.contains(data.callContext))
- dataLog("VALID");
+ dataLogF("VALID");
else
- dataLog("INVALID (due to argument creation)");
+ dataLogF("INVALID (due to argument creation)");
} else
- dataLog("INVALID (due to bad variable use)");
+ dataLogF("INVALID (due to bad variable use)");
}
- dataLog("\n");
+ dataLogF("\n");
}
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
index 699902a16..3bfb6a43e 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
@@ -29,24 +29,52 @@
#if ENABLE(DFG_JIT)
#include "DFGAbstractValue.h"
+#include "DFGGraph.h"
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 +90,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,52 +135,124 @@ 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;
+ }
+}
+
+Structure* ArrayMode::originalArrayStructure(Graph& graph, const CodeOrigin& codeOrigin) const
+{
+ if (!isJSArrayWithOriginalStructure())
+ return 0;
- 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);
+ JSGlobalObject* globalObject = graph.globalObjectFor(codeOrigin);
- return ArrayMode(Array::Generic);
+ switch (type()) {
+ case Array::Int32:
+ return globalObject->originalArrayStructureForIndexingType(ArrayWithInt32);
+ case Array::Double:
+ return globalObject->originalArrayStructureForIndexingType(ArrayWithDouble);
+ case Array::Contiguous:
+ return globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
+ case Array::ArrayStorage:
+ return globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage);
+ default:
+ CRASH();
+ return 0;
+ }
+}
+
+Structure* ArrayMode::originalArrayStructure(Graph& graph, Node& node) const
+{
+ return originalArrayStructure(graph, node.codeOrigin);
+}
+
+bool ArrayMode::alreadyChecked(Graph& graph, Node& node, AbstractValue& value, IndexingType shape) const
+{
+ switch (arrayClass()) {
+ case Array::OriginalArray:
+ return value.m_currentKnownStructure.hasSingleton()
+ && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape
+ && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray)
+ && graph.globalObjectFor(node.codeOrigin)->isOriginalArrayStructure(value.m_currentKnownStructure.singleton());
+
+ case Array::Array:
+ 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);
+
+ default:
+ 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
+bool ArrayMode::alreadyChecked(Graph& graph, Node& node, AbstractValue& value) const
{
switch (type()) {
case Array::Generic:
@@ -161,44 +264,37 @@ bool ArrayMode::alreadyChecked(AbstractValue& value) const
case Array::String:
return speculationChecked(value.m_type, SpecString);
+ case Array::Int32:
+ return alreadyChecked(graph, node, value, Int32Shape);
+
+ case Array::Double:
+ return alreadyChecked(graph, node, 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(graph, node, 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(graph, node, value, ArrayStorageShape);
case Array::SlowPutArrayStorage:
- if (isJSArray()) {
+ switch (arrayClass()) {
+ case Array::OriginalArray:
+ CRASH();
+ return false;
+
+ case Array::Array:
if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
return true;
return value.m_currentKnownStructure.hasSingleton()
&& hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
&& (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
+
+ default:
+ if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
+ return true;
+ return value.m_currentKnownStructure.hasSingleton()
+ && hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
}
- if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
- return true;
- return value.m_currentKnownStructure.hasSingleton()
- && hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
case Array::Arguments:
return speculationChecked(value.m_type, SpecArguments);
@@ -232,6 +328,7 @@ bool ArrayMode::alreadyChecked(AbstractValue& value) const
case Array::SelectUsingPredictions:
case Array::Unprofiled:
+ case Array::Undecided:
break;
}
@@ -252,6 +349,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:
@@ -306,6 +409,8 @@ const char* arrayClassToString(Array::Class arrayClass)
const char* arraySpeculationToString(Array::Speculation speculation)
{
switch (speculation) {
+ case Array::SaneChain:
+ return "SaneChain";
case Array::InBounds:
return "InBounds";
case Array::ToHole:
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h
index 615965c92..0799868d6 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.h
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h
@@ -33,9 +33,15 @@
#include "ArrayProfile.h"
#include "SpeculatedType.h"
-namespace JSC { namespace DFG {
+namespace JSC {
+struct CodeOrigin;
+
+namespace DFG {
+
+class Graph;
struct AbstractValue;
+struct Node;
// Use a namespace + enum instead of enum alone to avoid the namespace collision
// that would otherwise occur, since we say things like "Int8Array" and "JSArray"
@@ -52,7 +58,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,
@@ -77,11 +86,11 @@ enum Class {
};
enum Speculation {
- InBounds,
- ToHole,
- OutOfBounds
+ SaneChain, // In bounds and the array prototype chain is still intact, i.e. loading a hole doesn't require special treatment.
+ InBounds, // In bounds and not loading a hole.
+ ToHole, // Potentially storing to a hole.
+ OutOfBounds // Out-of-bounds access and anything can happen.
};
-
enum Conversion {
AsIs,
Convert
@@ -159,7 +168,7 @@ public:
mySpeculation = Array::InBounds;
if (isJSArray()) {
- if (profile->usesOriginalArrayStructures())
+ if (profile->usesOriginalArrayStructures() && benefitsFromOriginalArray())
myArrayClass = Array::OriginalArray;
else
myArrayClass = Array::Array;
@@ -169,15 +178,27 @@ 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());
+ }
- bool alreadyChecked(AbstractValue&) const;
+ 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(Graph&, Node&, AbstractValue&) const;
const char* toString() const;
bool usesButterfly() const
{
switch (type()) {
+ case Array::Int32:
+ case Array::Double:
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
@@ -203,9 +224,20 @@ public:
return arrayClass() == Array::OriginalArray;
}
+ bool isSaneChain() const
+ {
+ return speculation() == Array::SaneChain;
+ }
+
bool isInBounds() const
{
- return speculation() == Array::InBounds;
+ switch (speculation()) {
+ case Array::SaneChain:
+ case Array::InBounds:
+ return true;
+ default:
+ return false;
+ }
}
bool mayStoreToHole() const
@@ -263,6 +295,7 @@ public:
case Array::Unprofiled:
case Array::ForceExit:
case Array::Generic:
+ case Array::Undecided:
return false;
default:
return true;
@@ -277,6 +310,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:
@@ -286,6 +321,23 @@ public:
}
}
+ bool benefitsFromOriginalArray() const
+ {
+ switch (type()) {
+ case Array::Int32:
+ case Array::Double:
+ case Array::Contiguous:
+ case Array::ArrayStorage:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ // Returns 0 if this is not OriginalArray.
+ Structure* originalArrayStructure(Graph&, const CodeOrigin&) const;
+ Structure* originalArrayStructure(Graph&, Node&) const;
+
bool benefitsFromStructureCheck() const
{
switch (type()) {
@@ -309,6 +361,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 +410,8 @@ private:
}
}
+ bool alreadyChecked(Graph&, Node&, 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..9b879b9e3 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -218,7 +218,7 @@ private:
if (operand == JSStack::Callee)
return getCallee();
-
+
// Is this an argument?
if (operandIsArgument(operand))
return getArgument(operand);
@@ -256,7 +256,7 @@ private:
m_inlineStackTop->m_lazyOperands.prediction(
LazyOperandValueProfileKey(m_currentIndex, node.local()));
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Lazy operand [@%u, bc#%u, r%d] prediction: %s\n",
+ dataLogF("Lazy operand [@%u, bc#%u, r%d] prediction: %s\n",
nodeIndex, m_currentIndex, node.local(), speculationToString(prediction));
#endif
node.variableAccessData()->predict(prediction);
@@ -876,7 +876,7 @@ private:
SpeculatedType prediction = m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(bytecodeIndex);
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Dynamic [@%u, bc#%u] prediction: %s\n", nodeIndex, bytecodeIndex, speculationToString(prediction));
+ dataLogF("Dynamic [@%u, bc#%u] prediction: %s\n", nodeIndex, bytecodeIndex, speculationToString(prediction));
#endif
return prediction;
@@ -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)
@@ -917,8 +922,8 @@ private:
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
if (m_inlineStackTop->m_profiledBlock->numberOfRareCaseProfiles())
- dataLog("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter);
- dataLog("Array profile for bc#%u: %p%s%s, %u\n", m_currentIndex, profile->expectedStructure(), profile->structureIsPolymorphic() ? " (polymorphic)" : "", profile->mayInterceptIndexedAccesses() ? " (may intercept)" : "", profile->observedArrayModes());
+ dataLogF("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter);
+ dataLogF("Array profile for bc#%u: %p%s%s, %u\n", m_currentIndex, profile->expectedStructure(), profile->structureIsPolymorphic() ? " (polymorphic)" : "", profile->mayInterceptIndexedAccesses() ? " (may intercept)" : "", profile->observedArrayModes());
#endif
bool makeSafe =
@@ -962,13 +967,13 @@ private:
if (m_inlineStackTop->m_profiledBlock->likelyToTakeDeepestSlowCase(m_currentIndex)
|| m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)) {
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Making ArithMul @%u take deepest slow case.\n", nodeIndex);
+ dataLogF("Making ArithMul @%u take deepest slow case.\n", nodeIndex);
#endif
m_graph[nodeIndex].mergeFlags(NodeMayOverflow | NodeMayNegZero);
} else if (m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex)
|| m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero)) {
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Making ArithMul @%u take faster slow case.\n", nodeIndex);
+ dataLogF("Making ArithMul @%u take faster slow case.\n", nodeIndex);
#endif
m_graph[nodeIndex].mergeFlags(NodeMayNegZero);
}
@@ -998,7 +1003,7 @@ private:
return nodeIndex;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Making %s @%u safe at bc#%u because special fast-case counter is at %u and exit profiles say %d, %d\n", Graph::opName(m_graph[nodeIndex].op()), nodeIndex, m_currentIndex, m_inlineStackTop->m_profiledBlock->specialFastCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero));
+ dataLogF("Making %s @%u safe at bc#%u because special fast-case counter is at %u and exit profiles say %d, %d\n", Graph::opName(m_graph[nodeIndex].op()), nodeIndex, m_currentIndex, m_inlineStackTop->m_profiledBlock->specialFastCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero));
#endif
// FIXME: It might be possible to make this more granular. The DFG certainly can
@@ -1272,19 +1277,19 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn
m_inlineStackTop->m_profiledBlock, m_currentIndex);
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("For call at @%lu bc#%u: ", m_graph.size(), m_currentIndex);
+ dataLogF("For call at @%lu bc#%u: ", m_graph.size(), m_currentIndex);
if (callLinkStatus.isSet()) {
if (callLinkStatus.couldTakeSlowPath())
- dataLog("could take slow path, ");
- dataLog("target = %p\n", callLinkStatus.callTarget());
+ dataLogF("could take slow path, ");
+ dataLogF("target = %p\n", callLinkStatus.callTarget());
} else
- dataLog("not set.\n");
+ dataLogF("not set.\n");
#endif
if (m_graph.isFunctionConstant(callTarget)) {
callType = ConstantFunction;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Call at [@%lu, bc#%u] has a function constant: %p, exec %p.\n",
+ dataLogF("Call at [@%lu, bc#%u] has a function constant: %p, exec %p.\n",
m_graph.size(), m_currentIndex,
m_graph.valueOfFunctionConstant(callTarget),
m_graph.valueOfFunctionConstant(callTarget)->executable());
@@ -1292,7 +1297,7 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn
} else if (m_graph.isInternalFunctionConstant(callTarget)) {
callType = ConstantInternalFunction;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Call at [@%lu, bc#%u] has an internal function constant: %p.\n",
+ dataLogF("Call at [@%lu, bc#%u] has an internal function constant: %p.\n",
m_graph.size(), m_currentIndex,
m_graph.valueOfInternalFunctionConstant(callTarget));
#endif
@@ -1300,14 +1305,14 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn
&& !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) {
callType = LinkedFunction;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Call at [@%lu, bc#%u] is linked to: %p, exec %p.\n",
+ dataLogF("Call at [@%lu, bc#%u] is linked to: %p, exec %p.\n",
m_graph.size(), m_currentIndex, callLinkStatus.callTarget(),
callLinkStatus.callTarget()->executable());
#endif
} else {
callType = UnknownFunction;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Call at [@%lu, bc#%u] is has an unknown or ambiguous target.\n",
+ dataLogF("Call at [@%lu, bc#%u] is has an unknown or ambiguous target.\n",
m_graph.size(), m_currentIndex);
#endif
}
@@ -1432,7 +1437,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
ASSERT(canInlineFunctionFor(codeBlock, kind));
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Inlining executable %p.\n", executable);
+ dataLogF("Inlining executable %p.\n", executable);
#endif
// Now we know without a doubt that we are committed to inlining. So begin the process
@@ -1517,7 +1522,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
// caller. It doesn't need to be linked to, but it needs outgoing links.
if (!inlineStackEntry.m_unlinkedBlocks.isEmpty()) {
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Reascribing bytecode index of block %p from bc#%u to bc#%u (inline return case).\n", lastBlock, lastBlock->bytecodeBegin, m_currentIndex);
+ dataLogF("Reascribing bytecode index of block %p from bc#%u to bc#%u (inline return case).\n", lastBlock, lastBlock->bytecodeBegin, m_currentIndex);
#endif
// For debugging purposes, set the bytecodeBegin. Note that this doesn't matter
// for release builds because this block will never serve as a potential target
@@ -1529,7 +1534,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
m_currentBlock = m_graph.m_blocks.last().get();
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Done inlining executable %p, continuing code generation at epilogue.\n", executable);
+ dataLogF("Done inlining executable %p, continuing code generation at epilogue.\n", executable);
#endif
return true;
}
@@ -1556,7 +1561,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
// Need to create a new basic block for the continuation at the caller.
OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(nextOffset, m_numArguments, m_numLocals));
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Creating inline epilogue basic block %p, #%zu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame));
+ dataLogF("Creating inline epilogue basic block %p, #%zu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame));
#endif
m_currentBlock = block.get();
ASSERT(m_inlineStackTop->m_caller->m_blockLinkingTargets.isEmpty() || m_graph.m_blocks[m_inlineStackTop->m_caller->m_blockLinkingTargets.last()]->bytecodeBegin < nextOffset);
@@ -1568,7 +1573,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
// At this point we return and continue to generate code for the caller, but
// in the new basic block.
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Done inlining executable %p, continuing code generation in new block.\n", executable);
+ dataLogF("Done inlining executable %p, continuing code generation in new block.\n", executable);
#endif
return true;
}
@@ -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)));
@@ -1689,7 +1703,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
int thisOperand = registerOffset + argumentToOperand(0);
int indexOperand = registerOffset + argumentToOperand(1);
- NodeIndex charCode = addToGraph(StringCharCodeAt, OpInfo(Array::String), get(thisOperand), getToInt32(indexOperand));
+ NodeIndex charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), getToInt32(indexOperand));
if (usesResult)
set(resultOperand, charCode);
@@ -1702,7 +1716,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
int thisOperand = registerOffset + argumentToOperand(0);
int indexOperand = registerOffset + argumentToOperand(1);
- NodeIndex charCode = addToGraph(StringCharAt, OpInfo(Array::String), get(thisOperand), getToInt32(indexOperand));
+ NodeIndex charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), getToInt32(indexOperand));
if (usesResult)
set(resultOperand, charCode);
@@ -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;
}
@@ -2063,7 +2077,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
addToGraph(Jump, OpInfo(m_currentIndex));
else {
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Refusing to plant jump at limit %u because block %p is empty.\n", limit, m_currentBlock);
+ dataLogF("Refusing to plant jump at limit %u because block %p is empty.\n", limit, m_currentBlock);
#endif
}
return shouldContinueParsing;
@@ -2090,9 +2104,9 @@ bool ByteCodeParser::parseBlock(unsigned limit)
m_inlineStackTop->m_profiledBlock->valueProfileForBytecodeOffset(m_currentProfilingIndex);
profile->computeUpdatedPrediction();
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("[@%lu bc#%u]: profile %p: ", m_graph.size(), m_currentProfilingIndex, profile);
+ dataLogF("[@%lu bc#%u]: profile %p: ", m_graph.size(), m_currentProfilingIndex, profile);
profile->dump(WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
#endif
if (profile->m_singletonValueIsTop
|| !profile->m_singletonValue
@@ -2110,36 +2124,65 @@ bool ByteCodeParser::parseBlock(unsigned limit)
}
case op_create_this: {
- set(currentInstruction[1].u.operand, addToGraph(CreateThis, get(JSStack::Callee)));
+ int calleeOperand = currentInstruction[2].u.operand;
+ NodeIndex callee = get(calleeOperand);
+ bool alreadyEmitted = false;
+ if (m_graph[callee].op() == WeakJSConstant) {
+ JSCell* cell = m_graph[callee].weakConstant();
+ ASSERT(cell->inherits(&JSFunction::s_info));
+
+ JSFunction* function = jsCast<JSFunction*>(cell);
+ Structure* inheritorID = function->tryGetKnownInheritorID();
+ if (inheritorID) {
+ addToGraph(InheritorIDWatchpoint, OpInfo(function));
+ set(currentInstruction[1].u.operand, addToGraph(NewObject, OpInfo(inheritorID)));
+ alreadyEmitted = true;
+ }
+ }
+ if (!alreadyEmitted)
+ set(currentInstruction[1].u.operand, addToGraph(CreateThis, callee));
NEXT_OPCODE(op_create_this);
}
case op_new_object: {
- set(currentInstruction[1].u.operand, addToGraph(NewObject));
+ set(currentInstruction[1].u.operand, addToGraph(NewObject, OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->emptyObjectStructure())));
NEXT_OPCODE(op_new_object);
}
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);
@@ -2150,6 +2193,22 @@ bool ByteCodeParser::parseBlock(unsigned limit)
NEXT_OPCODE(op_new_regexp);
}
+ case op_get_callee: {
+ ValueProfile* profile = currentInstruction[2].u.profile;
+ profile->computeUpdatedPrediction();
+ if (profile->m_singletonValueIsTop
+ || !profile->m_singletonValue
+ || !profile->m_singletonValue.isCell())
+ set(currentInstruction[1].u.operand, get(JSStack::Callee));
+ else {
+ ASSERT(profile->m_singletonValue.asCell()->inherits(&JSFunction::s_info));
+ NodeIndex actualCallee = get(JSStack::Callee);
+ addToGraph(CheckFunction, OpInfo(profile->m_singletonValue.asCell()), actualCallee);
+ set(currentInstruction[1].u.operand, addToGraph(WeakJSConstant, OpInfo(profile->m_singletonValue.asCell())));
+ }
+ NEXT_OPCODE(op_get_callee);
+ }
+
// === Bitwise operations ===
case op_bitand: {
@@ -3215,12 +3274,12 @@ void ByteCodeParser::processPhiStack()
VariableAccessData* dataForPhi = m_graph[entry.m_phi].variableAccessData();
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Handling phi entry for var %u, phi @%u.\n", entry.m_varNo, entry.m_phi);
+ dataLogF(" Handling phi entry for var %u, phi @%u.\n", entry.m_varNo, entry.m_phi);
#endif
for (size_t i = 0; i < predecessors.size(); ++i) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Dealing with predecessor block %u.\n", predecessors[i]);
+ dataLogF(" Dealing with predecessor block %u.\n", predecessors[i]);
#endif
BasicBlock* predecessorBlock = m_graph.m_blocks[predecessors[i]].get();
@@ -3230,7 +3289,7 @@ void ByteCodeParser::processPhiStack()
NodeIndex valueInPredecessor = var;
if (valueInPredecessor == NoNode) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Did not find node, adding phi.\n");
+ dataLogF(" Did not find node, adding phi.\n");
#endif
valueInPredecessor = insertPhiNode(OpInfo(newVariableAccessData(stackType == ArgumentPhiStack ? argumentToOperand(varNo) : static_cast<int>(varNo), false)), predecessorBlock);
@@ -3242,7 +3301,7 @@ void ByteCodeParser::processPhiStack()
phiStack.append(PhiStackEntry(predecessorBlock, valueInPredecessor, varNo));
} else if (m_graph[valueInPredecessor].op() == GetLocal) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Found GetLocal @%u.\n", valueInPredecessor);
+ dataLogF(" Found GetLocal @%u.\n", valueInPredecessor);
#endif
// We want to ensure that the VariableAccessDatas are identical between the
@@ -3254,7 +3313,7 @@ void ByteCodeParser::processPhiStack()
valueInPredecessor = m_graph[valueInPredecessor].child1().index();
} else {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Found @%u.\n", valueInPredecessor);
+ dataLogF(" Found @%u.\n", valueInPredecessor);
#endif
}
ASSERT(m_graph[valueInPredecessor].op() == SetLocal
@@ -3269,48 +3328,48 @@ void ByteCodeParser::processPhiStack()
Node* phiNode = &m_graph[entry.m_phi];
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Ref count of @%u = %u.\n", entry.m_phi, phiNode->refCount());
+ dataLogF(" Ref count of @%u = %u.\n", entry.m_phi, phiNode->refCount());
#endif
if (phiNode->refCount()) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Reffing @%u.\n", valueInPredecessor);
+ dataLogF(" Reffing @%u.\n", valueInPredecessor);
#endif
m_graph.ref(valueInPredecessor);
}
if (!phiNode->child1()) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Setting @%u->child1 = @%u.\n", entry.m_phi, valueInPredecessor);
+ dataLogF(" Setting @%u->child1 = @%u.\n", entry.m_phi, valueInPredecessor);
#endif
phiNode->children.setChild1(Edge(valueInPredecessor));
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Children of @%u: ", entry.m_phi);
+ dataLogF(" Children of @%u: ", entry.m_phi);
phiNode->dumpChildren(WTF::dataFile());
- dataLog(".\n");
+ dataLogF(".\n");
#endif
continue;
}
if (!phiNode->child2()) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Setting @%u->child2 = @%u.\n", entry.m_phi, valueInPredecessor);
+ dataLogF(" Setting @%u->child2 = @%u.\n", entry.m_phi, valueInPredecessor);
#endif
phiNode->children.setChild2(Edge(valueInPredecessor));
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Children of @%u: ", entry.m_phi);
+ dataLogF(" Children of @%u: ", entry.m_phi);
phiNode->dumpChildren(WTF::dataFile());
- dataLog(".\n");
+ dataLogF(".\n");
#endif
continue;
}
if (!phiNode->child3()) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Setting @%u->child3 = @%u.\n", entry.m_phi, valueInPredecessor);
+ dataLogF(" Setting @%u->child3 = @%u.\n", entry.m_phi, valueInPredecessor);
#endif
phiNode->children.setChild3(Edge(valueInPredecessor));
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Children of @%u: ", entry.m_phi);
+ dataLogF(" Children of @%u: ", entry.m_phi);
phiNode->dumpChildren(WTF::dataFile());
- dataLog(".\n");
+ dataLogF(".\n");
#endif
continue;
}
@@ -3318,7 +3377,7 @@ void ByteCodeParser::processPhiStack()
NodeIndex newPhi = insertPhiNode(OpInfo(dataForPhi), entry.m_block);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Splitting @%u, created @%u.\n", entry.m_phi, newPhi);
+ dataLogF(" Splitting @%u, created @%u.\n", entry.m_phi, newPhi);
#endif
phiNode = &m_graph[entry.m_phi]; // reload after vector resize
@@ -3329,17 +3388,17 @@ void ByteCodeParser::processPhiStack()
newPhiNode.children = phiNode->children;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Children of @%u: ", newPhi);
+ dataLogF(" Children of @%u: ", newPhi);
newPhiNode.dumpChildren(WTF::dataFile());
- dataLog(".\n");
+ dataLogF(".\n");
#endif
phiNode->children.initialize(newPhi, valueInPredecessor, NoNode);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Children of @%u: ", entry.m_phi);
+ dataLogF(" Children of @%u: ", entry.m_phi);
phiNode->dumpChildren(WTF::dataFile());
- dataLog(".\n");
+ dataLogF(".\n");
#endif
}
}
@@ -3366,7 +3425,7 @@ void ByteCodeParser::linkBlock(BasicBlock* block, Vector<BlockIndex>& possibleTa
case Jump:
node.setTakenBlockIndex(m_graph.blockIndexForBytecodeOffset(possibleTargets, node.takenBytecodeOffsetDuringParsing()));
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Linked basic block %p to %p, #%u.\n", block, m_graph.m_blocks[node.takenBlockIndex()].get(), node.takenBlockIndex());
+ dataLogF("Linked basic block %p to %p, #%u.\n", block, m_graph.m_blocks[node.takenBlockIndex()].get(), node.takenBlockIndex());
#endif
break;
@@ -3374,13 +3433,13 @@ void ByteCodeParser::linkBlock(BasicBlock* block, Vector<BlockIndex>& possibleTa
node.setTakenBlockIndex(m_graph.blockIndexForBytecodeOffset(possibleTargets, node.takenBytecodeOffsetDuringParsing()));
node.setNotTakenBlockIndex(m_graph.blockIndexForBytecodeOffset(possibleTargets, node.notTakenBytecodeOffsetDuringParsing()));
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Linked basic block %p to %p, #%u and %p, #%u.\n", block, m_graph.m_blocks[node.takenBlockIndex()].get(), node.takenBlockIndex(), m_graph.m_blocks[node.notTakenBlockIndex()].get(), node.notTakenBlockIndex());
+ dataLogF("Linked basic block %p to %p, #%u and %p, #%u.\n", block, m_graph.m_blocks[node.takenBlockIndex()].get(), node.takenBlockIndex(), m_graph.m_blocks[node.notTakenBlockIndex()].get(), node.notTakenBlockIndex());
#endif
break;
default:
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Marking basic block %p as linked.\n", block);
+ dataLogF("Marking basic block %p as linked.\n", block);
#endif
break;
}
@@ -3489,9 +3548,9 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
}
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Current captured variables: ");
+ dataLogF("Current captured variables: ");
inlineCallFrame.capturedVars.dump(WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
#endif
byteCodeParser->m_codeBlock->inlineCallFrames().append(inlineCallFrame);
@@ -3598,7 +3657,7 @@ void ByteCodeParser::parseCodeBlock()
CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Parsing code block %p. codeType = %s, captureCount = %u, needsFullScopeChain = %s, needsActivation = %s, isStrictMode = %s\n",
+ dataLogF("Parsing code block %p. codeType = %s, captureCount = %u, needsFullScopeChain = %s, needsActivation = %s, isStrictMode = %s\n",
codeBlock,
codeTypeToString(codeBlock->codeType()),
codeBlock->symbolTable() ? codeBlock->symbolTable()->captureCount() : 0,
@@ -3612,7 +3671,7 @@ void ByteCodeParser::parseCodeBlock()
// The maximum bytecode offset to go into the current basicblock is either the next jump target, or the end of the instructions.
unsigned limit = jumpTargetIndex < codeBlock->numberOfJumpTargets() ? codeBlock->jumpTarget(jumpTargetIndex) : codeBlock->instructions().size();
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Parsing bytecode with limit %p bc#%u at inline depth %u.\n", m_inlineStackTop->executable(), limit, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame));
+ dataLogF("Parsing bytecode with limit %p bc#%u at inline depth %u.\n", m_inlineStackTop->executable(), limit, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame));
#endif
ASSERT(m_currentIndex < limit);
@@ -3634,13 +3693,13 @@ void ByteCodeParser::parseCodeBlock()
// Change its bytecode begin and continue.
m_currentBlock = m_graph.m_blocks.last().get();
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Reascribing bytecode index of block %p from bc#%u to bc#%u (peephole case).\n", m_currentBlock, m_currentBlock->bytecodeBegin, m_currentIndex);
+ dataLogF("Reascribing bytecode index of block %p from bc#%u to bc#%u (peephole case).\n", m_currentBlock, m_currentBlock->bytecodeBegin, m_currentIndex);
#endif
m_currentBlock->bytecodeBegin = m_currentIndex;
} else {
OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(m_currentIndex, m_numArguments, m_numLocals));
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Creating basic block %p, #%zu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame));
+ dataLogF("Creating basic block %p, #%zu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame));
#endif
m_currentBlock = block.get();
ASSERT(m_inlineStackTop->m_unlinkedBlocks.isEmpty() || m_graph.m_blocks[m_inlineStackTop->m_unlinkedBlocks.last().m_blockIndex]->bytecodeBegin < m_currentIndex);
@@ -3697,14 +3756,14 @@ bool ByteCodeParser::parse()
linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets);
m_graph.determineReachability();
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Processing local variable phis.\n");
+ dataLogF("Processing local variable phis.\n");
#endif
m_currentProfilingIndex = m_currentIndex;
processPhiStack<LocalPhiStack>();
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Processing argument phis.\n");
+ dataLogF("Processing argument phis.\n");
#endif
processPhiStack<ArgumentPhiStack>();
diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
index a2570b7ea..8adde0598 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)
@@ -485,6 +535,20 @@ public:
moveDouble(ARMRegisters::d2, FPRInfo::argumentFPR1);
}
}
+
+ 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);
+ }
#else
ALWAYS_INLINE void setupArguments(FPRReg arg1)
{
@@ -496,6 +560,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 +714,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 +809,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);
@@ -779,6 +871,12 @@ public:
setupArgumentsWithExecState(arg1, arg2, arg3);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4)
+ {
+ poke(arg4);
+ setupArgumentsWithExecState(arg1, arg2, arg3);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4, GPRReg arg5)
{
poke(arg5, 1);
@@ -786,6 +884,13 @@ public:
setupArgumentsWithExecState(arg1, arg2, arg3);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4, TrustedImm32 arg5)
+ {
+ poke(arg5, 1);
+ poke(arg4);
+ setupArgumentsWithExecState(arg1, arg2, arg3);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, TrustedImmPtr arg5)
{
poke(arg5, 1);
diff --git a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
index 24ea0b36f..1a88066d1 100644
--- a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
@@ -78,47 +78,47 @@ private:
if (!block->cfaShouldRevisit)
return;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Block #%u (bc#%u):\n", blockIndex, block->bytecodeBegin);
+ dataLogF(" Block #%u (bc#%u):\n", blockIndex, block->bytecodeBegin);
#endif
m_state.beginBasicBlock(block);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" head vars: ");
+ dataLogF(" head vars: ");
dumpOperands(block->valuesAtHead, WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
#endif
for (unsigned i = 0; i < block->size(); ++i) {
NodeIndex nodeIndex = block->at(i);
if (!m_graph[nodeIndex].shouldGenerate())
continue;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" %s @%u: ", Graph::opName(m_graph[nodeIndex].op()), nodeIndex);
+ dataLogF(" %s @%u: ", Graph::opName(m_graph[nodeIndex].op()), nodeIndex);
m_state.dump(WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
#endif
if (!m_state.execute(i)) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Expect OSR exit.\n");
+ dataLogF(" Expect OSR exit.\n");
#endif
break;
}
}
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" tail regs: ");
+ dataLogF(" tail regs: ");
m_state.dump(WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
#endif
m_changed |= m_state.endBasicBlock(AbstractState::MergeToSuccessors);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" tail vars: ");
+ dataLogF(" tail vars: ");
dumpOperands(block->valuesAtTail, WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
#endif
}
void performForwardCFA()
{
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("CFA [%u]\n", ++m_count);
+ dataLogF("CFA [%u]\n", ++m_count);
#endif
for (BlockIndex block = 0; block < m_graph.m_blocks.size(); ++block)
diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
index e0d973992..d9ae4a274 100644
--- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
@@ -66,7 +66,7 @@ public:
ASSERT(m_graph.m_blocks[m_graph.successor(block, 0)]->m_predecessors[0]
== blockIndex);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("CFGSimplify: Jump merge on Block #%u to Block #%u.\n",
+ dataLogF("CFGSimplify: Jump merge on Block #%u to Block #%u.\n",
blockIndex, m_graph.successor(block, 0));
#endif
if (extremeLogging)
@@ -76,14 +76,14 @@ public:
break;
} else {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Not jump merging on Block #%u to Block #%u because predecessors = ",
+ dataLogF("Not jump merging on Block #%u to Block #%u because predecessors = ",
blockIndex, m_graph.successor(block, 0));
for (unsigned i = 0; i < m_graph.m_blocks[m_graph.successor(block, 0)]->m_predecessors.size(); ++i) {
if (i)
- dataLog(", ");
- dataLog("#%u", m_graph.m_blocks[m_graph.successor(block, 0)]->m_predecessors[i]);
+ dataLogF(", ");
+ dataLogF("#%u", m_graph.m_blocks[m_graph.successor(block, 0)]->m_predecessors[i]);
}
- dataLog(".\n");
+ dataLogF(".\n");
#endif
}
@@ -99,14 +99,13 @@ 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) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("CFGSimplify: Known condition (%s) branch merge on Block #%u to Block #%u, jettisoning Block #%u.\n",
+ dataLogF("CFGSimplify: Known condition (%s) branch merge on Block #%u to Block #%u, jettisoning Block #%u.\n",
condition ? "true" : "false",
blockIndex, m_graph.successorForCondition(block, condition),
m_graph.successorForCondition(block, !condition));
@@ -119,7 +118,7 @@ public:
m_graph.successorForCondition(block, !condition));
} else {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("CFGSimplify: Known condition (%s) branch->jump conversion on Block #%u to Block #%u, jettisoning Block #%u.\n",
+ dataLogF("CFGSimplify: Known condition (%s) branch->jump conversion on Block #%u to Block #%u, jettisoning Block #%u.\n",
condition ? "true" : "false",
blockIndex, m_graph.successorForCondition(block, condition),
m_graph.successorForCondition(block, !condition));
@@ -153,13 +152,13 @@ public:
ASSERT(targetBlock->isReachable);
if (targetBlock->m_predecessors.size() == 1) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("CFGSimplify: Branch to same successor merge on Block #%u to Block #%u.\n",
+ dataLogF("CFGSimplify: Branch to same successor merge on Block #%u to Block #%u.\n",
blockIndex, targetBlockIndex);
#endif
mergeBlocks(blockIndex, targetBlockIndex, NoBlock);
} else {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("CFGSimplify: Branch->jump conversion to same successor on Block #%u to Block #%u.\n",
+ dataLogF("CFGSimplify: Branch->jump conversion to same successor on Block #%u to Block #%u.\n",
blockIndex, targetBlockIndex);
#endif
ASSERT(m_graph[block->last()].isTerminal());
@@ -180,7 +179,7 @@ public:
}
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Not branch simplifying on Block #%u because the successors differ and the condition is not known.\n",
+ dataLogF("Not branch simplifying on Block #%u because the successors differ and the condition is not known.\n",
blockIndex);
#endif
@@ -288,22 +287,22 @@ private:
if (child.op() != GetLocal)
return;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Considering GetLocal at @%u, local r%d.\n", edge.index(), child.local());
+ dataLogF(" Considering GetLocal at @%u, local r%d.\n", edge.index(), child.local());
#endif
if (child.variableAccessData()->isCaptured()) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" It's captured.\n");
+ dataLogF(" It's captured.\n");
#endif
return;
}
NodeIndex originalNodeIndex = block->variablesAtTail.operand(child.local());
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Dealing with original @%u.\n", originalNodeIndex);
+ dataLogF(" Dealing with original @%u.\n", originalNodeIndex);
#endif
ASSERT(originalNodeIndex != NoNode);
Node* originalNode = &m_graph[originalNodeIndex];
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Original has local r%d.\n", originalNode->local());
+ dataLogF(" Original has local r%d.\n", originalNode->local());
#endif
ASSERT(child.local() == originalNode->local());
if (changeRef)
@@ -328,14 +327,14 @@ private:
switch (originalNode->op()) {
case SetLocal: {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" It's a SetLocal.\n");
+ dataLogF(" It's a SetLocal.\n");
#endif
m_graph.changeIndex(edge, originalNode->child1().index(), changeRef);
break;
}
case GetLocal: {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" It's a GetLocal.\n");
+ dataLogF(" It's a GetLocal.\n");
#endif
m_graph.changeIndex(edge, originalNodeIndex, changeRef);
break;
@@ -343,7 +342,7 @@ private:
case Phi:
case SetArgument: {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" It's Phi/SetArgument.\n");
+ dataLogF(" It's Phi/SetArgument.\n");
#endif
// Keep the GetLocal!
break;
@@ -381,7 +380,7 @@ private:
Node& phiNode = m_graph[phiNodeIndex];
NodeIndex myNodeIndex = sourceBlock->variablesAtTail.operand(phiNode.local());
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Considering removing reference from phi @%u to @%u on local r%d:",
+ dataLogF("Considering removing reference from phi @%u to @%u on local r%d:",
phiNodeIndex, myNodeIndex, phiNode.local());
#endif
if (myNodeIndex == NoNode) {
@@ -395,7 +394,7 @@ private:
for (unsigned j = 0; j < AdjacencyList::Size; ++j)
removePotentiallyDeadPhiReference(myNodeIndex, phiNode, j, sourceBlock->isReachable);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("\n");
+ dataLogF("\n");
#endif
}
}
@@ -403,7 +402,7 @@ private:
void fixJettisonedPredecessors(BlockIndex blockIndex, BlockIndex jettisonedBlockIndex)
{
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Fixing predecessors and phis due to jettison of Block #%u from Block #%u.\n",
+ dataLogF("Fixing predecessors and phis due to jettison of Block #%u from Block #%u.\n",
jettisonedBlockIndex, blockIndex);
#endif
BasicBlock* jettisonedBlock = m_graph.m_blocks[jettisonedBlockIndex].get();
@@ -423,7 +422,7 @@ private:
if (phiNode.children.child(edgeIndex).indexUnchecked() != myNodeIndex)
return;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Removing reference at child %u.", edgeIndex);
+ dataLogF(" Removing reference at child %u.", edgeIndex);
#endif
if (changeRef && phiNode.shouldGenerate())
m_graph.deref(myNodeIndex);
@@ -711,7 +710,7 @@ private:
bool changeRef = phiNode.shouldGenerate();
OperandSubstitution substitution = substitutions.operand(phiNode.local());
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Performing operand substitution @%u -> @%u.\n",
+ dataLogF(" Performing operand substitution @%u -> @%u.\n",
substitution.oldChild, substitution.newChild);
#endif
if (!phiNode.child1())
@@ -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/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index 19051c174..36acb2c21 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -79,7 +79,7 @@ private:
result++;
ASSERT(result <= m_indexInBlock);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" limit %u: ", result);
+ dataLogF(" limit %u: ", result);
#endif
return result;
}
@@ -372,7 +372,7 @@ private:
return NoNode;
}
- bool checkFunctionElimination(JSFunction* function, NodeIndex child1)
+ bool checkFunctionElimination(JSCell* function, NodeIndex child1)
{
for (unsigned i = endIndexForPureCSE(); i--;) {
NodeIndex index = m_currentBlock->at(i);
@@ -970,7 +970,7 @@ private:
return false;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Replacing @%u -> @%u", m_compileIndex, replacement);
+ dataLogF(" Replacing @%u -> @%u", m_compileIndex, replacement);
#endif
Node& node = m_graph[m_compileIndex];
@@ -988,7 +988,7 @@ private:
void eliminate()
{
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Eliminating @%u", m_compileIndex);
+ dataLogF(" Eliminating @%u", m_compileIndex);
#endif
Node& node = m_graph[m_compileIndex];
@@ -1029,7 +1029,7 @@ private:
return;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" %s @%u: ", Graph::opName(m_graph[m_compileIndex].op()), m_compileIndex);
+ dataLogF(" %s @%u: ", Graph::opName(m_graph[m_compileIndex].op()), m_compileIndex);
#endif
// NOTE: there are some nodes that we deliberately don't CSE even though we
@@ -1043,6 +1043,10 @@ private:
switch (node.op()) {
+ case Identity:
+ setReplacement(node.child1().index());
+ break;
+
// Handle the pure nodes. These nodes never have any side-effects.
case BitAnd:
case BitOr:
@@ -1313,7 +1317,7 @@ private:
m_lastSeen[node.op()] = m_indexInBlock;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("\n");
+ dataLogF("\n");
#endif
}
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/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index 910c3d986..869751372 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -38,7 +38,7 @@ static inline void debugFail(CodeBlock* codeBlock, OpcodeID opcodeID, bool resul
{
ASSERT_UNUSED(result, !result);
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Cannot handle code block %p because of opcode %s.\n", codeBlock, opcodeNames[opcodeID]);
+ dataLogF("Cannot handle code block %p because of opcode %s.\n", codeBlock, opcodeNames[opcodeID]);
#else
UNUSED_PARAM(codeBlock);
UNUSED_PARAM(opcodeID);
@@ -51,10 +51,10 @@ static inline void debugFail(CodeBlock* codeBlock, OpcodeID opcodeID, Capability
ASSERT(result != CanCompile);
#if DFG_ENABLE(DEBUG_VERBOSE)
if (result == CannotCompile)
- dataLog("Cannot handle code block %p because of opcode %s.\n", codeBlock, opcodeNames[opcodeID]);
+ dataLogF("Cannot handle code block %p because of opcode %s.\n", codeBlock, opcodeNames[opcodeID]);
else {
ASSERT(result == ShouldProfile);
- dataLog("Cannot compile code block %p because of opcode %s, but inlining might be possible.\n", codeBlock, opcodeNames[opcodeID]);
+ dataLogF("Cannot compile code block %p because of opcode %s, but inlining might be possible.\n", codeBlock, opcodeNames[opcodeID]);
}
#else
UNUSED_PARAM(codeBlock);
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.h b/Source/JavaScriptCore/dfg/DFGCapabilities.h
index 1f9778efe..a89c697f6 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.h
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.h
@@ -116,6 +116,7 @@ inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instructi
case op_enter:
case op_convert_this:
case op_create_this:
+ case op_get_callee:
case op_bitand:
case op_bitor:
case op_bitxor:
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h
index c3726ed85..2c0556d60 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.h
+++ b/Source/JavaScriptCore/dfg/DFGCommon.h
@@ -135,11 +135,6 @@ enum NoResultTag { NoResult };
enum OptimizationFixpointState { BeforeFixpoint, FixpointNotConverged, FixpointConverged };
-inline bool shouldShowDisassembly()
-{
- return Options::showDisassembly() || Options::showDFGDisassembly();
-}
-
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
@@ -150,6 +145,16 @@ namespace JSC { namespace DFG {
enum CapabilityLevel { CannotCompile, ShouldProfile, CanCompile, CapabilityLevelNotSet };
+// Unconditionally disable DFG disassembly support if the DFG is not compiled in.
+inline bool shouldShowDisassembly()
+{
+#if ENABLE(DFG_JIT)
+ return Options::showDisassembly() || Options::showDFGDisassembly();
+#else
+ return false;
+#endif
+}
+
} } // namespace JSC::DFG
#endif // DFGCommon_h
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index 43aa2c007..2221954b5 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -33,6 +33,8 @@
#include "DFGGraph.h"
#include "DFGInsertionSet.h"
#include "DFGPhase.h"
+#include "GetByIdStatus.h"
+#include "PutByIdStatus.h"
namespace JSC { namespace DFG {
@@ -65,7 +67,7 @@ private:
bool foldConstants(BlockIndex blockIndex)
{
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Constant folding considering Block #%u.\n", blockIndex);
+ dataLogF("Constant folding considering Block #%u.\n", blockIndex);
#endif
BasicBlock* block = m_graph.m_blocks[blockIndex].get();
bool changed = false;
@@ -109,14 +111,16 @@ private:
StructureAbstractValue& structureValue = value.m_futurePossibleStructure;
if (structureValue.isSubsetOf(set)
&& structureValue.hasSingleton()
- && isCellSpeculation(value.m_type))
+ && isCellSpeculation(value.m_type)) {
node.convertToStructureTransitionWatchpoint(structureValue.singleton());
+ changed = true;
+ }
break;
}
case CheckArray:
case Arrayify: {
- if (!node.arrayMode().alreadyChecked(m_state.forNode(node.child1())))
+ if (!node.arrayMode().alreadyChecked(m_graph, node, m_state.forNode(node.child1())))
break;
ASSERT(node.refCount() == 1);
node.setOpAndDefaultFlags(Phantom);
@@ -124,6 +128,206 @@ private:
break;
}
+ case CheckFunction: {
+ if (m_state.forNode(node.child1()).value() != node.function())
+ break;
+ node.setOpAndDefaultFlags(Phantom);
+ eliminated = true;
+ break;
+ }
+
+ case ConvertThis: {
+ if (!isObjectSpeculation(m_state.forNode(node.child1()).m_type))
+ break;
+ node.setOpAndDefaultFlags(Identity);
+ changed = true;
+ break;
+ }
+
+ case GetById:
+ case GetByIdFlush: {
+ CodeOrigin codeOrigin = node.codeOrigin;
+ NodeIndex child = node.child1().index();
+ unsigned identifierNumber = node.identifierNumber();
+
+ if (!isCellSpeculation(m_graph[child].prediction()))
+ break;
+
+ Structure* structure = m_state.forNode(child).bestProvenStructure();
+ if (!structure)
+ break;
+
+ bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton();
+
+ GetByIdStatus status = GetByIdStatus::computeFor(
+ globalData(), structure, codeBlock()->identifier(identifierNumber));
+
+ if (!status.isSimple())
+ break;
+
+ ASSERT(status.structureSet().size() == 1);
+ ASSERT(status.chain().isEmpty());
+ ASSERT(status.structureSet().singletonStructure() == structure);
+
+ // Now before we do anything else, push the CFA forward over the GetById
+ // and make sure we signal to the loop that it should continue and not
+ // do any eliminations.
+ m_state.execute(indexInBlock);
+ eliminated = true;
+
+ if (needsWatchpoint) {
+ ASSERT(m_state.forNode(child).m_futurePossibleStructure.isSubsetOf(StructureSet(structure)));
+ m_graph[child].ref();
+ Node watchpoint(StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), child);
+ watchpoint.ref();
+ NodeIndex watchpointIndex = m_graph.size();
+ m_graph.append(watchpoint);
+ m_insertionSet.append(indexInBlock, watchpointIndex);
+ }
+
+ NodeIndex propertyStorageIndex;
+
+ m_graph[child].ref();
+ if (isInlineOffset(status.offset()))
+ propertyStorageIndex = child;
+ else {
+ Node getButterfly(GetButterfly, codeOrigin, child);
+ getButterfly.ref();
+ propertyStorageIndex = m_graph.size();
+ m_graph.append(getButterfly);
+ m_insertionSet.append(indexInBlock, propertyStorageIndex);
+ }
+
+ m_graph[nodeIndex].convertToGetByOffset(m_graph.m_storageAccessData.size(), propertyStorageIndex);
+
+ StorageAccessData storageAccessData;
+ storageAccessData.offset = indexRelativeToBase(status.offset());
+ storageAccessData.identifierNumber = identifierNumber;
+ m_graph.m_storageAccessData.append(storageAccessData);
+ break;
+ }
+
+ case PutById:
+ case PutByIdDirect: {
+ CodeOrigin codeOrigin = node.codeOrigin;
+ NodeIndex child = node.child1().index();
+ unsigned identifierNumber = node.identifierNumber();
+
+ Structure* structure = m_state.forNode(child).bestProvenStructure();
+ if (!structure)
+ break;
+
+ bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton();
+
+ PutByIdStatus status = PutByIdStatus::computeFor(
+ globalData(),
+ m_graph.globalObjectFor(codeOrigin),
+ structure,
+ codeBlock()->identifier(identifierNumber),
+ node.op() == PutByIdDirect);
+
+ if (!status.isSimpleReplace() && !status.isSimpleTransition())
+ break;
+
+ ASSERT(status.oldStructure() == structure);
+
+ // Now before we do anything else, push the CFA forward over the PutById
+ // and make sure we signal to the loop that it should continue and not
+ // do any eliminations.
+ m_state.execute(indexInBlock);
+ eliminated = true;
+
+ if (needsWatchpoint) {
+ ASSERT(m_state.forNode(child).m_futurePossibleStructure.isSubsetOf(StructureSet(structure)));
+ m_graph[child].ref();
+ Node watchpoint(StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), child);
+ watchpoint.ref();
+ NodeIndex watchpointIndex = m_graph.size();
+ m_graph.append(watchpoint);
+ m_insertionSet.append(indexInBlock, watchpointIndex);
+ }
+
+ StructureTransitionData* transitionData = 0;
+ if (status.isSimpleTransition()) {
+ transitionData = m_graph.addStructureTransitionData(
+ StructureTransitionData(structure, status.newStructure()));
+
+ if (node.op() == PutById) {
+ if (!structure->storedPrototype().isNull()) {
+ addStructureTransitionCheck(
+ codeOrigin, indexInBlock,
+ structure->storedPrototype().asCell());
+ }
+
+ for (WriteBarrier<Structure>* it = status.structureChain()->head(); *it; ++it) {
+ JSValue prototype = (*it)->storedPrototype();
+ if (prototype.isNull())
+ continue;
+ ASSERT(prototype.isCell());
+ addStructureTransitionCheck(
+ codeOrigin, indexInBlock, prototype.asCell());
+ }
+ }
+ }
+
+ NodeIndex propertyStorageIndex;
+
+ m_graph[child].ref();
+ if (isInlineOffset(status.offset()))
+ propertyStorageIndex = child;
+ else if (status.isSimpleReplace() || structure->outOfLineCapacity() == status.newStructure()->outOfLineCapacity()) {
+ Node getButterfly(GetButterfly, codeOrigin, child);
+ getButterfly.ref();
+ propertyStorageIndex = m_graph.size();
+ m_graph.append(getButterfly);
+ m_insertionSet.append(indexInBlock, propertyStorageIndex);
+ } else if (!structure->outOfLineCapacity()) {
+ ASSERT(status.newStructure()->outOfLineCapacity());
+ ASSERT(!isInlineOffset(status.offset()));
+ Node allocateStorage(AllocatePropertyStorage, codeOrigin, OpInfo(transitionData), child);
+ allocateStorage.ref(); // Once for the use.
+ allocateStorage.ref(); // Twice because it's must-generate.
+ propertyStorageIndex = m_graph.size();
+ m_graph.append(allocateStorage);
+ m_insertionSet.append(indexInBlock, propertyStorageIndex);
+ } else {
+ ASSERT(structure->outOfLineCapacity());
+ ASSERT(status.newStructure()->outOfLineCapacity() > structure->outOfLineCapacity());
+ ASSERT(!isInlineOffset(status.offset()));
+
+ Node getButterfly(GetButterfly, codeOrigin, child);
+ getButterfly.ref();
+ NodeIndex getButterflyIndex = m_graph.size();
+ m_graph.append(getButterfly);
+ m_insertionSet.append(indexInBlock, getButterflyIndex);
+
+ m_graph[child].ref();
+ Node reallocateStorage(ReallocatePropertyStorage, codeOrigin, OpInfo(transitionData), child, getButterflyIndex);
+ reallocateStorage.ref(); // Once for the use.
+ reallocateStorage.ref(); // Twice because it's must-generate.
+ propertyStorageIndex = m_graph.size();
+ m_graph.append(reallocateStorage);
+ m_insertionSet.append(indexInBlock, propertyStorageIndex);
+ }
+
+ if (status.isSimpleTransition()) {
+ m_graph[child].ref();
+ Node putStructure(PutStructure, codeOrigin, OpInfo(transitionData), child);
+ putStructure.ref();
+ NodeIndex putStructureIndex = m_graph.size();
+ m_graph.append(putStructure);
+ m_insertionSet.append(indexInBlock, putStructureIndex);
+ }
+
+ m_graph[nodeIndex].convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorageIndex);
+
+ StorageAccessData storageAccessData;
+ storageAccessData.offset = indexRelativeToBase(status.offset());
+ storageAccessData.identifierNumber = identifierNumber;
+ m_graph.m_storageAccessData.append(storageAccessData);
+ break;
+ }
+
default:
break;
}
@@ -213,6 +417,31 @@ private:
return changed;
}
+ void addStructureTransitionCheck(CodeOrigin codeOrigin, unsigned indexInBlock, JSCell* cell)
+ {
+ Node weakConstant(WeakJSConstant, codeOrigin, OpInfo(cell));
+ weakConstant.ref();
+ weakConstant.predict(speculationFromValue(cell));
+ NodeIndex weakConstantIndex = m_graph.size();
+ m_graph.append(weakConstant);
+ m_insertionSet.append(indexInBlock, weakConstantIndex);
+
+ if (cell->structure()->transitionWatchpointSetIsStillValid()) {
+ Node watchpoint(StructureTransitionWatchpoint, codeOrigin, OpInfo(cell->structure()), weakConstantIndex);
+ watchpoint.ref();
+ NodeIndex watchpointIndex = m_graph.size();
+ m_graph.append(watchpoint);
+ m_insertionSet.append(indexInBlock, watchpointIndex);
+ return;
+ }
+
+ Node check(CheckStructure, codeOrigin, OpInfo(m_graph.addStructureSet(cell->structure())), weakConstantIndex);
+ check.ref();
+ NodeIndex checkIndex = m_graph.size();
+ m_graph.append(check);
+ m_insertionSet.append(indexInBlock, checkIndex);
+ }
+
// This is necessary because the CFA may reach conclusions about constants based on its
// assumption that certain code must exit, but then those constants may lead future
// reexecutions of the CFA to believe that the same code will now no longer exit. Thus
@@ -225,7 +454,7 @@ private:
bool changed = false;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Painting unreachable code in Block #%u.\n", blockIndex);
+ dataLogF("Painting unreachable code in Block #%u.\n", blockIndex);
#endif
BasicBlock* block = m_graph.m_blocks[blockIndex].get();
m_state.beginBasicBlock(block);
diff --git a/Source/JavaScriptCore/dfg/DFGDisassembler.cpp b/Source/JavaScriptCore/dfg/DFGDisassembler.cpp
index cfbb936b8..654824196 100644
--- a/Source/JavaScriptCore/dfg/DFGDisassembler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDisassembler.cpp
@@ -43,8 +43,8 @@ void Disassembler::dump(LinkBuffer& linkBuffer)
{
m_graph.m_dominators.computeIfNecessary(m_graph);
- dataLog("Generated JIT code for DFG CodeBlock %p, instruction count = %u:\n", m_graph.m_codeBlock, m_graph.m_codeBlock->instructionCount());
- dataLog(" Code at [%p, %p):\n", linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize());
+ dataLogF("Generated JIT code for DFG CodeBlock %p, instruction count = %u:\n", m_graph.m_codeBlock, m_graph.m_codeBlock->instructionCount());
+ dataLogF(" Code at [%p, %p):\n", linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize());
const char* prefix = " ";
const char* disassemblyPrefix = " ";
@@ -82,7 +82,7 @@ void Disassembler::dump(LinkBuffer& linkBuffer)
}
}
dumpDisassembly(disassemblyPrefix, linkBuffer, previousLabel, m_endOfMainPath, lastNodeIndex);
- dataLog("%s(End Of Main Path)\n", prefix);
+ dataLogF("%s(End Of Main Path)\n", prefix);
dumpDisassembly(disassemblyPrefix, linkBuffer, previousLabel, m_endOfCode, NoNode);
}
@@ -104,10 +104,7 @@ void Disassembler::dumpDisassembly(const char* prefix, LinkBuffer& linkBuffer, M
CodeLocationLabel end = linkBuffer.locationOf(currentLabel);
previousLabel = currentLabel;
ASSERT(bitwise_cast<uintptr_t>(end.executableAddress()) >= bitwise_cast<uintptr_t>(start.executableAddress()));
- if (tryToDisassemble(start, bitwise_cast<uintptr_t>(end.executableAddress()) - bitwise_cast<uintptr_t>(start.executableAddress()), prefixBuffer.get(), WTF::dataFile()))
- return;
-
- dataLog("%s disassembly not available for range %p...%p\n", prefixBuffer.get(), start.executableAddress(), end.executableAddress());
+ disassemble(start, bitwise_cast<uintptr_t>(end.executableAddress()) - bitwise_cast<uintptr_t>(start.executableAddress()), prefixBuffer.get(), WTF::dataFile());
}
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp
index eb68fa344..8645c6dce 100644
--- a/Source/JavaScriptCore/dfg/DFGDriver.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp
@@ -72,7 +72,7 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
return false;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("DFG compiling code block %p(%p) for executable %p, number of instructions = %u.\n", codeBlock, codeBlock->alternative(), codeBlock->ownerExecutable(), codeBlock->instructionCount());
+ dataLogF("DFG compiling code block %p(%p) for executable %p, number of instructions = %u.\n", codeBlock, codeBlock->alternative(), codeBlock->ownerExecutable(), codeBlock->instructionCount());
#endif
// Derive our set of must-handle values. The compilation must be at least conservative
@@ -119,7 +119,7 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
dfg.m_fixpointState = FixpointNotConverged;
for (;; ++cnt) {
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("DFG beginning optimization fixpoint iteration #%u.\n", cnt);
+ dataLogF("DFG beginning optimization fixpoint iteration #%u.\n", cnt);
#endif
bool changed = false;
performCFA(dfg);
@@ -135,13 +135,13 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
dfg.m_fixpointState = FixpointConverged;
performCSE(dfg);
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("DFG optimization fixpoint converged in %u iterations.\n", cnt);
+ dataLogF("DFG optimization fixpoint converged in %u iterations.\n", cnt);
#endif
performVirtualRegisterAllocation(dfg);
GraphDumpMode modeForFinalValidate = DumpGraph;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Graph after optimization:\n");
+ dataLogF("Graph after optimization:\n");
dfg.dump();
modeForFinalValidate = DontDumpGraph;
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 5a76aa8df..1ba40def3 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -69,7 +69,7 @@ private:
NodeType op = node.op();
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" %s @%u: ", Graph::opName(op), m_compileIndex);
+ dataLogF(" %s @%u: ", Graph::opName(op), m_compileIndex);
#endif
switch (op) {
@@ -134,6 +134,17 @@ private:
m_graph[node.child2()].prediction()));
blessArrayOperation(node.child1(), node.child2(), 2);
+
+ Node* nodePtr = &m_graph[m_compileIndex];
+ ArrayMode arrayMode = nodePtr->arrayMode();
+ if (arrayMode.type() == Array::Double
+ && arrayMode.arrayClass() == Array::OriginalArray
+ && arrayMode.speculation() == Array::InBounds
+ && arrayMode.conversion() == Array::AsIs
+ && m_graph.globalObjectFor(nodePtr->codeOrigin)->arrayPrototypeChainIsSane()
+ && !(nodePtr->flags() & NodeUsedAsOther))
+ nodePtr->setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
+
break;
}
case StringCharAt:
@@ -145,7 +156,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 +270,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 +296,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 +313,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 +341,7 @@ private:
}
case ArithAbs: {
- if (m_graph[node.child1()].shouldSpeculateInteger()
+ if (m_graph[node.child1()].shouldSpeculateIntegerForArithmetic()
&& node.canSpeculateInteger())
break;
fixDoubleEdge(0);
@@ -328,13 +362,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,16 +393,29 @@ 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;
}
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
if (!(node.flags() & NodeHasVarArgs)) {
- dataLog("new children: ");
+ dataLogF("new children: ");
node.dumpChildren(WTF::dataFile());
}
- dataLog("\n");
+ dataLogF("\n");
#endif
}
@@ -384,29 +435,12 @@ private:
m_graph.ref(array);
+ Structure* structure = arrayMode.originalArrayStructure(m_graph, codeOrigin);
+
if (arrayMode.doesConversion()) {
if (index != NoNode)
m_graph.ref(index);
- Structure* structure = 0;
- if (arrayMode.isJSArrayWithOriginalStructure()) {
- JSGlobalObject* globalObject = m_graph.baselineCodeBlockFor(codeOrigin)->globalObject();
- switch (arrayMode.type()) {
- case Array::Contiguous:
- structure = globalObject->arrayStructure();
- if (structure->indexingType() != ArrayWithContiguous)
- structure = 0;
- break;
- case Array::ArrayStorage:
- structure = globalObject->arrayStructureWithArrayStorage();
- if (structure->indexingType() != ArrayWithArrayStorage)
- structure = 0;
- break;
- default:
- break;
- }
- }
-
if (structure) {
Node arrayify(ArrayifyToStructure, codeOrigin, OpInfo(structure), OpInfo(arrayMode.asWord()), array, index);
arrayify.ref();
@@ -421,11 +455,19 @@ private:
m_insertionSet.append(m_indexInBlock, arrayifyIndex);
}
} else {
- Node checkArray(CheckArray, codeOrigin, OpInfo(arrayMode.asWord()), array);
- checkArray.ref();
- NodeIndex checkArrayIndex = m_graph.size();
- m_graph.append(checkArray);
- m_insertionSet.append(m_indexInBlock, checkArrayIndex);
+ if (structure) {
+ Node checkStructure(CheckStructure, codeOrigin, OpInfo(m_graph.addStructureSet(structure)), array);
+ checkStructure.ref();
+ NodeIndex checkStructureIndex = m_graph.size();
+ m_graph.append(checkStructure);
+ m_insertionSet.append(m_indexInBlock, checkStructureIndex);
+ } else {
+ Node checkArray(CheckArray, codeOrigin, OpInfo(arrayMode.asWord()), array);
+ checkArray.ref();
+ NodeIndex checkArrayIndex = m_graph.size();
+ m_graph.append(checkArray);
+ m_insertionSet.append(m_indexInBlock, checkArrayIndex);
+ }
}
if (!storageCheck(arrayMode))
@@ -506,7 +548,7 @@ private:
NodeIndex resultIndex = (NodeIndex)m_graph.size();
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("(replacing @%u->@%u with @%u->@%u) ",
+ dataLogF("(replacing @%u->@%u with @%u->@%u) ",
m_compileIndex, edge.index(), m_compileIndex, resultIndex);
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 8e8817f81..19587ba64 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -98,7 +98,7 @@ const char* Graph::nameOfVariableAccessData(VariableAccessData* variableAccessDa
static void printWhiteSpace(unsigned amount)
{
while (amount-- > 0)
- dataLog(" ");
+ dataLogF(" ");
}
void Graph::dumpCodeOrigin(const char* prefix, NodeIndex prevNodeIndex, NodeIndex nodeIndex)
@@ -124,16 +124,16 @@ void Graph::dumpCodeOrigin(const char* prefix, NodeIndex prevNodeIndex, NodeInde
// Print the pops.
for (unsigned i = previousInlineStack.size(); i-- > indexOfDivergence;) {
- dataLog("%s", prefix);
+ dataLogF("%s", prefix);
printWhiteSpace(i * 2);
- dataLog("<-- %p\n", previousInlineStack[i].inlineCallFrame->executable.get());
+ dataLogF("<-- %p\n", previousInlineStack[i].inlineCallFrame->executable.get());
}
// Print the pushes.
for (unsigned i = indexOfDivergence; i < currentInlineStack.size(); ++i) {
- dataLog("%s", prefix);
+ dataLogF("%s", prefix);
printWhiteSpace(i * 2);
- dataLog("--> %p\n", currentInlineStack[i].inlineCallFrame->executable.get());
+ dataLogF("--> %p\n", currentInlineStack[i].inlineCallFrame->executable.get());
}
}
@@ -158,7 +158,7 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
if (mustGenerate)
--refCount;
- dataLog("%s", prefix);
+ dataLogF("%s", prefix);
printNodeWhiteSpace(node);
// Example/explanation of dataflow dump output
@@ -178,22 +178,22 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
// $# - the index in the CodeBlock of a constant { for numeric constants the value is displayed | for integers, in both decimal and hex }.
// id# - the index in the CodeBlock of an identifier { if codeBlock is passed to dump(), the string representation is displayed }.
// var# - the index of a var on the global object, used by GetGlobalVar/PutGlobalVar operations.
- dataLog("% 4d:%s<%c%u:", (int)nodeIndex, skipped ? " skipped " : " ", mustGenerate ? '!' : ' ', refCount);
+ dataLogF("% 4d:%s<%c%u:", (int)nodeIndex, skipped ? " skipped " : " ", mustGenerate ? '!' : ' ', refCount);
if (node.hasResult() && !skipped && node.hasVirtualRegister())
- dataLog("%u", node.virtualRegister());
+ dataLogF("%u", node.virtualRegister());
else
- dataLog("-");
- dataLog(">\t%s(", opName(op));
+ dataLogF("-");
+ dataLogF(">\t%s(", opName(op));
bool hasPrinted = false;
if (node.flags() & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++) {
if (hasPrinted)
- dataLog(", ");
+ dataLogF(", ");
else
hasPrinted = true;
if (!m_varArgChildren[childIdx])
continue;
- dataLog("%s@%u%s",
+ dataLogF("%s@%u%s",
useKindToString(m_varArgChildren[childIdx].useKind()),
m_varArgChildren[childIdx].index(),
speculationToAbbreviatedString(
@@ -201,19 +201,19 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
}
} else {
if (!!node.child1()) {
- dataLog("%s@%u%s",
+ dataLogF("%s@%u%s",
useKindToString(node.child1().useKind()),
node.child1().index(),
speculationToAbbreviatedString(at(node.child1()).prediction()));
}
if (!!node.child2()) {
- dataLog(", %s@%u%s",
+ dataLogF(", %s@%u%s",
useKindToString(node.child2().useKind()),
node.child2().index(),
speculationToAbbreviatedString(at(node.child2()).prediction()));
}
if (!!node.child3()) {
- dataLog(", %s@%u%s",
+ dataLogF(", %s@%u%s",
useKindToString(node.child3().useKind()),
node.child3().index(),
speculationToAbbreviatedString(at(node.child3()).prediction()));
@@ -222,47 +222,51 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
}
if (strlen(nodeFlagsAsString(node.flags()))) {
- dataLog("%s%s", hasPrinted ? ", " : "", nodeFlagsAsString(node.flags()));
+ dataLogF("%s%s", hasPrinted ? ", " : "", nodeFlagsAsString(node.flags()));
hasPrinted = true;
}
if (node.hasArrayMode()) {
- dataLog("%s%s", hasPrinted ? ", " : "", node.arrayMode().toString());
+ dataLogF("%s%s", hasPrinted ? ", " : "", node.arrayMode().toString());
hasPrinted = true;
}
if (node.hasVarNumber()) {
- dataLog("%svar%u", hasPrinted ? ", " : "", node.varNumber());
+ dataLogF("%svar%u", hasPrinted ? ", " : "", node.varNumber());
hasPrinted = true;
}
if (node.hasRegisterPointer()) {
- dataLog(
+ dataLogF(
"%sglobal%u(%p)", hasPrinted ? ", " : "",
globalObjectFor(node.codeOrigin)->findRegisterIndex(node.registerPointer()),
node.registerPointer());
hasPrinted = true;
}
if (node.hasIdentifier()) {
- dataLog("%sid%u{%s}", hasPrinted ? ", " : "", node.identifierNumber(), m_codeBlock->identifier(node.identifierNumber()).string().utf8().data());
+ dataLogF("%sid%u{%s}", hasPrinted ? ", " : "", node.identifierNumber(), m_codeBlock->identifier(node.identifierNumber()).string().utf8().data());
hasPrinted = true;
}
if (node.hasStructureSet()) {
for (size_t i = 0; i < node.structureSet().size(); ++i) {
- dataLog("%sstruct(%p: %s)", hasPrinted ? ", " : "", node.structureSet()[i], indexingTypeToString(node.structureSet()[i]->indexingType()));
+ dataLogF("%sstruct(%p: %s)", hasPrinted ? ", " : "", node.structureSet()[i], indexingTypeToString(node.structureSet()[i]->indexingType()));
hasPrinted = true;
}
}
if (node.hasStructure()) {
- dataLog("%sstruct(%p: %s)", hasPrinted ? ", " : "", node.structure(), indexingTypeToString(node.structure()->indexingType()));
+ dataLogF("%sstruct(%p: %s)", hasPrinted ? ", " : "", node.structure(), indexingTypeToString(node.structure()->indexingType()));
hasPrinted = true;
}
if (node.hasStructureTransitionData()) {
- dataLog("%sstruct(%p -> %p)", hasPrinted ? ", " : "", node.structureTransitionData().previousStructure, node.structureTransitionData().newStructure);
+ dataLogF("%sstruct(%p -> %p)", hasPrinted ? ", " : "", node.structureTransitionData().previousStructure, node.structureTransitionData().newStructure);
+ hasPrinted = true;
+ }
+ if (node.hasFunction()) {
+ dataLogF("%s%p", hasPrinted ? ", " : "", node.function());
hasPrinted = true;
}
if (node.hasStorageAccessData()) {
StorageAccessData& storageAccessData = m_storageAccessData[node.storageAccessDataIndex()];
- dataLog("%sid%u{%s}", hasPrinted ? ", " : "", storageAccessData.identifierNumber, m_codeBlock->identifier(storageAccessData.identifierNumber).string().utf8().data());
+ dataLogF("%sid%u{%s}", hasPrinted ? ", " : "", storageAccessData.identifierNumber, m_codeBlock->identifier(storageAccessData.identifierNumber).string().utf8().data());
- dataLog(", %lu", static_cast<unsigned long>(storageAccessData.offset));
+ dataLogF(", %lu", static_cast<unsigned long>(storageAccessData.offset));
hasPrinted = true;
}
ASSERT(node.hasVariableAccessData() == node.hasLocal());
@@ -270,100 +274,105 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
VariableAccessData* variableAccessData = node.variableAccessData();
int operand = variableAccessData->operand();
if (operandIsArgument(operand))
- dataLog("%sarg%u(%s)", hasPrinted ? ", " : "", operandToArgument(operand), nameOfVariableAccessData(variableAccessData));
+ dataLogF("%sarg%u(%s)", hasPrinted ? ", " : "", operandToArgument(operand), nameOfVariableAccessData(variableAccessData));
else
- dataLog("%sr%u(%s)", hasPrinted ? ", " : "", operand, nameOfVariableAccessData(variableAccessData));
+ dataLogF("%sr%u(%s)", hasPrinted ? ", " : "", operand, nameOfVariableAccessData(variableAccessData));
hasPrinted = true;
}
if (node.hasConstantBuffer()) {
if (hasPrinted)
- dataLog(", ");
- dataLog("%u:[", node.startConstant());
+ dataLogF(", ");
+ dataLogF("%u:[", node.startConstant());
for (unsigned i = 0; i < node.numConstants(); ++i) {
if (i)
- dataLog(", ");
- dataLog("%s", m_codeBlock->constantBuffer(node.startConstant())[i].description());
+ dataLogF(", ");
+ dataLogF("%s", m_codeBlock->constantBuffer(node.startConstant())[i].description());
}
- dataLog("]");
+ dataLogF("]");
hasPrinted = true;
}
+ if (node.hasIndexingType()) {
+ if (hasPrinted)
+ dataLogF(", ");
+ dataLogF("%s", indexingTypeToString(node.indexingType()));
+ }
if (op == JSConstant) {
- dataLog("%s$%u", hasPrinted ? ", " : "", node.constantNumber());
+ dataLogF("%s$%u", hasPrinted ? ", " : "", node.constantNumber());
JSValue value = valueOfJSConstant(nodeIndex);
- dataLog(" = %s", value.description());
+ dataLogF(" = %s", value.description());
hasPrinted = true;
}
if (op == WeakJSConstant) {
- dataLog("%s%p", hasPrinted ? ", " : "", node.weakConstant());
+ dataLogF("%s%p", hasPrinted ? ", " : "", node.weakConstant());
hasPrinted = true;
}
if (node.isBranch() || node.isJump()) {
- dataLog("%sT:#%u", hasPrinted ? ", " : "", node.takenBlockIndex());
+ dataLogF("%sT:#%u", hasPrinted ? ", " : "", node.takenBlockIndex());
hasPrinted = true;
}
if (node.isBranch()) {
- dataLog("%sF:#%u", hasPrinted ? ", " : "", node.notTakenBlockIndex());
+ dataLogF("%sF:#%u", hasPrinted ? ", " : "", node.notTakenBlockIndex());
hasPrinted = true;
}
- dataLog("%sbc#%u", hasPrinted ? ", " : "", node.codeOrigin.bytecodeIndex);
+ dataLogF("%sbc#%u", hasPrinted ? ", " : "", node.codeOrigin.bytecodeIndex);
hasPrinted = true;
(void)hasPrinted;
- dataLog(")");
+ dataLogF(")");
if (!skipped) {
if (node.hasVariableAccessData())
- dataLog(" predicting %s%s", speculationToString(node.variableAccessData()->prediction()), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : "");
+ dataLogF(" predicting %s%s", speculationToString(node.variableAccessData()->prediction()), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : "");
else if (node.hasHeapPrediction())
- dataLog(" predicting %s", speculationToString(node.getHeapPrediction()));
+ dataLogF(" predicting %s", speculationToString(node.getHeapPrediction()));
}
- dataLog("\n");
+ dataLogF("\n");
}
void Graph::dumpBlockHeader(const char* prefix, BlockIndex blockIndex, PhiNodeDumpMode phiNodeDumpMode)
{
BasicBlock* block = m_blocks[blockIndex].get();
- dataLog("%sBlock #%u (bc#%u): %s%s\n", prefix, (int)blockIndex, block->bytecodeBegin, block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : "");
- dataLog("%s Predecessors:", prefix);
+ dataLogF("%sBlock #%u (bc#%u): %s%s\n", prefix, (int)blockIndex, block->bytecodeBegin, block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : "");
+ dataLogF("%s Predecessors:", prefix);
for (size_t i = 0; i < block->m_predecessors.size(); ++i)
- dataLog(" #%u", block->m_predecessors[i]);
- dataLog("\n");
+ dataLogF(" #%u", block->m_predecessors[i]);
+ dataLogF("\n");
if (m_dominators.isValid()) {
- dataLog("%s Dominated by:", prefix);
+ dataLogF("%s Dominated by:", prefix);
for (size_t i = 0; i < m_blocks.size(); ++i) {
if (!m_dominators.dominates(i, blockIndex))
continue;
- dataLog(" #%lu", static_cast<unsigned long>(i));
+ dataLogF(" #%lu", static_cast<unsigned long>(i));
}
- dataLog("\n");
- dataLog("%s Dominates:", prefix);
+ dataLogF("\n");
+ dataLogF("%s Dominates:", prefix);
for (size_t i = 0; i < m_blocks.size(); ++i) {
if (!m_dominators.dominates(blockIndex, i))
continue;
- dataLog(" #%lu", static_cast<unsigned long>(i));
+ dataLogF(" #%lu", static_cast<unsigned long>(i));
}
- dataLog("\n");
+ dataLogF("\n");
}
- dataLog("%s Phi Nodes:", prefix);
+ dataLogF("%s Phi Nodes:", prefix);
for (size_t i = 0; i < block->phis.size(); ++i) {
NodeIndex phiNodeIndex = block->phis[i];
Node& phiNode = at(phiNodeIndex);
if (!phiNode.shouldGenerate() && phiNodeDumpMode == DumpLivePhisOnly)
continue;
- dataLog(" @%u->(", phiNodeIndex);
+ dataLogF(" @%u->(", phiNodeIndex);
if (phiNode.child1()) {
- dataLog("@%u", phiNode.child1().index());
+ dataLogF("@%u", phiNode.child1().index());
if (phiNode.child2()) {
- dataLog(", @%u", phiNode.child2().index());
+ dataLogF(", @%u", phiNode.child2().index());
if (phiNode.child3())
- dataLog(", @%u", phiNode.child3().index());
+ dataLogF(", @%u", phiNode.child3().index());
}
}
- dataLog(")%s", i + 1 < block->phis.size() ? "," : "");
+ dataLogF(")%s", i + 1 < block->phis.size() ? "," : "");
}
- dataLog("\n");
+ dataLogF("\n");
}
void Graph::dump()
@@ -374,29 +383,29 @@ void Graph::dump()
if (!block)
continue;
dumpBlockHeader("", b, DumpAllPhis);
- dataLog(" vars before: ");
+ dataLogF(" vars before: ");
if (block->cfaHasVisited)
dumpOperands(block->valuesAtHead, WTF::dataFile());
else
- dataLog("<empty>");
- dataLog("\n");
- dataLog(" var links: ");
+ dataLogF("<empty>");
+ dataLogF("\n");
+ dataLogF(" var links: ");
dumpOperands(block->variablesAtHead, WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
for (size_t i = 0; i < block->size(); ++i) {
dumpCodeOrigin("", lastNodeIndex, block->at(i));
dump("", block->at(i));
lastNodeIndex = block->at(i);
}
- dataLog(" vars after: ");
+ dataLogF(" vars after: ");
if (block->cfaHasVisited)
dumpOperands(block->valuesAtTail, WTF::dataFile());
else
- dataLog("<empty>");
- dataLog("\n");
- dataLog(" var links: ");
+ dataLogF("<empty>");
+ dataLogF("\n");
+ dataLogF(" var links: ");
dumpOperands(block->variablesAtTail, WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
}
}
@@ -451,7 +460,7 @@ void Graph::predictArgumentTypes()
at(m_arguments[arg]).variableAccessData()->predict(profile->computeUpdatedPrediction());
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Argument [%zu] prediction: %s\n", arg, speculationToString(at(m_arguments[arg]).variableAccessData()->prediction()));
+ dataLogF("Argument [%zu] prediction: %s\n", arg, speculationToString(at(m_arguments[arg]).variableAccessData()->prediction()));
#endif
}
}
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 9fbb2df07..0c77b2959 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)
@@ -230,18 +230,13 @@ public:
Node& left = at(mul.child1());
Node& right = at(mul.child2());
- if (left.hasConstant())
- return mulImmediateShouldSpeculateInteger(mul, right, left);
- 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();
}
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 +488,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 +709,7 @@ private:
if (!immediateValue.isNumber())
return false;
- if (!variable.shouldSpeculateInteger())
+ if (!variable.shouldSpeculateIntegerExpectingDefined())
return false;
if (immediateValue.isInt32())
@@ -734,7 +731,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/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
index c7f941a7a..191aa7fe5 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
@@ -128,7 +128,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
{
// Link the code, populate data in CodeBlock data structures.
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("JIT code for %p start at [%p, %p). Size = %zu.\n", m_codeBlock, linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize(), linkBuffer.debugSize());
+ dataLogF("JIT code for %p start at [%p, %p). Size = %zu.\n", m_codeBlock, linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize(), linkBuffer.debugSize());
#endif
// Link all calls out from the JIT code to their respective functions.
@@ -188,11 +188,12 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
CallLinkInfo& info = m_codeBlock->callLinkInfo(i);
info.callType = m_jsCalls[i].m_callType;
info.isDFG = true;
- info.bytecodeIndex = m_jsCalls[i].m_codeOrigin.bytecodeIndex;
+ info.codeOrigin = m_jsCalls[i].m_codeOrigin;
linkBuffer.link(m_jsCalls[i].m_slowCall, FunctionPtr((m_globalData->getCTIStub(info.callType == CallLinkInfo::Construct ? linkConstructThunkGenerator : linkCallThunkGenerator)).code().executableAddress()));
info.callReturnLocation = linkBuffer.locationOfNearCall(m_jsCalls[i].m_slowCall);
info.hotPathBegin = linkBuffer.locationOf(m_jsCalls[i].m_targetToCheck);
info.hotPathOther = linkBuffer.locationOfNearCall(m_jsCalls[i].m_fastCall);
+ info.calleeGPR = static_cast<unsigned>(m_jsCalls[i].m_callee);
}
MacroAssemblerCodeRef osrExitThunk = globalData()->getCTIStub(osrExitGenerationThunkGenerator);
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
index c73934832..0bd88b788 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
@@ -357,9 +357,9 @@ public:
m_propertyAccesses.append(record);
}
- void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, CodeOrigin codeOrigin)
+ void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, GPRReg callee, CodeOrigin codeOrigin)
{
- m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, callType, codeOrigin));
+ m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, callType, callee, codeOrigin));
}
void addWeakReference(JSCell* target)
@@ -440,11 +440,12 @@ private:
Vector<CallExceptionRecord> m_exceptionChecks;
struct JSCallRecord {
- JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, CodeOrigin codeOrigin)
+ JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, GPRReg callee, CodeOrigin codeOrigin)
: m_fastCall(fastCall)
, m_slowCall(slowCall)
, m_targetToCheck(targetToCheck)
, m_callType(callType)
+ , m_callee(callee)
, m_codeOrigin(codeOrigin)
{
}
@@ -453,6 +454,7 @@ private:
Call m_slowCall;
DataLabelPtr m_targetToCheck;
CallLinkInfo::CallType m_callType;
+ GPRReg m_callee;
CodeOrigin m_codeOrigin;
};
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index e66629ec4..18c8ce16f 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;
@@ -268,6 +269,26 @@ struct Node {
convertToStructureTransitionWatchpoint(structureSet().singletonStructure());
}
+ void convertToGetByOffset(unsigned storageAccessDataIndex, NodeIndex storage)
+ {
+ ASSERT(m_op == GetById || m_op == GetByIdFlush);
+ m_opInfo = storageAccessDataIndex;
+ children.setChild1(Edge(storage));
+ m_op = GetByOffset;
+ m_flags &= ~NodeClobbersWorld;
+ }
+
+ void convertToPutByOffset(unsigned storageAccessDataIndex, NodeIndex storage)
+ {
+ ASSERT(m_op == PutById || m_op == PutByIdDirect);
+ m_opInfo = storageAccessDataIndex;
+ children.setChild3(children.child2());
+ children.setChild2(children.child1());
+ children.setChild1(Edge(storage));
+ m_op = PutByOffset;
+ m_flags &= ~NodeClobbersWorld;
+ }
+
JSCell* weakConstant()
{
ASSERT(op() == WeakJSConstant);
@@ -433,6 +454,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;
@@ -518,6 +565,11 @@ struct Node {
return (m_flags & NodeResultMask) == NodeResultBoolean;
}
+ bool hasStorageResult()
+ {
+ return (m_flags & NodeResultMask) == NodeResultStorage;
+ }
+
bool isJump()
{
return op() == Jump;
@@ -649,15 +701,23 @@ struct Node {
return mergeSpeculation(m_opInfo2, prediction);
}
- bool hasFunctionCheckData()
+ bool hasFunction()
{
- return op() == CheckFunction;
+ switch (op()) {
+ case CheckFunction:
+ case InheritorIDWatchpoint:
+ return true;
+ default:
+ return false;
+ }
}
- JSFunction* function()
+ JSCell* function()
{
- ASSERT(hasFunctionCheckData());
- return reinterpret_cast<JSFunction*>(m_opInfo);
+ ASSERT(hasFunction());
+ JSCell* result = reinterpret_cast<JSFunction*>(m_opInfo);
+ ASSERT(JSValue(result).isFunction());
+ return result;
}
bool hasStructureTransitionData()
@@ -702,6 +762,7 @@ struct Node {
case StructureTransitionWatchpoint:
case ForwardStructureTransitionWatchpoint:
case ArrayifyToStructure:
+ case NewObject:
return true;
default:
return false;
@@ -922,16 +983,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 +1118,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/DFGNodeFlags.cpp b/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
index 480a7dab9..fb83c5a71 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
+++ b/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
@@ -112,6 +112,12 @@ const char* nodeFlagsAsString(NodeFlags flags)
ptr.strcat("PureNum");
hasPrinted = true;
}
+ if (flags & NodeUsedAsOther) {
+ if (hasPrinted)
+ ptr.strcat("|");
+ ptr.strcat("UseAsOther");
+ hasPrinted = true;
+ }
}
if (flags & NodeMayOverflow) {
diff --git a/Source/JavaScriptCore/dfg/DFGNodeFlags.h b/Source/JavaScriptCore/dfg/DFGNodeFlags.h
index a897d0c4f..5e41bfc6b 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeFlags.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeFlags.h
@@ -52,14 +52,15 @@ namespace JSC { namespace DFG {
#define NodeMayOverflow 0x100
#define NodeMayNegZero 0x200
-#define NodeBackPropMask 0x1C00
+#define NodeBackPropMask 0x3C00
#define NodeUseBottom 0x000
#define NodeUsedAsNumber 0x400 // The result of this computation may be used in a context that observes fractional results.
#define NodeNeedsNegZero 0x800 // The result of this computation may be used in a context that observes -0.
-#define NodeUsedAsValue (NodeUsedAsNumber | NodeNeedsNegZero)
-#define NodeUsedAsInt 0x1000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
+#define NodeUsedAsOther 0x1000 // The result of this computation may be used in a context that distinguishes between NaN and other things (like undefined).
+#define NodeUsedAsValue (NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther)
+#define NodeUsedAsInt 0x2000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
-#define NodeDoesNotExit 0x2000 // This flag is negated to make it natural for the default to be that a node does exit.
+#define NodeDoesNotExit 0x4000 // This flag is negated to make it natural for the default to be that a node does exit.
typedef uint16_t NodeFlags;
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 624b1ae75..cbcdde660 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -43,6 +43,11 @@ namespace JSC { namespace DFG {
/* code block. */\
macro(WeakJSConstant, NodeResultJS | NodeDoesNotExit) \
\
+ /* Marker to indicate that an operation was optimized entirely and all that is left */\
+ /* is to make one node alias another. CSE will later usually eliminate this node, */\
+ /* though it may choose not to if it would corrupt predictions (very rare). */\
+ macro(Identity, NodeResultJS | NodeDoesNotExit) \
+ \
/* Nodes for handling functions (both as call and as construct). */\
macro(ConvertThis, NodeResultJS) \
macro(CreateThis, NodeResultJS) /* Note this is not MustGenerate since we're returning it anyway. */ \
@@ -154,6 +159,7 @@ namespace JSC { namespace DFG {
macro(GlobalVarWatchpoint, NodeMustGenerate) \
macro(PutGlobalVarCheck, NodeMustGenerate) \
macro(CheckFunction, NodeMustGenerate) \
+ macro(InheritorIDWatchpoint, NodeMustGenerate) \
\
/* Optimizations for array mutation. */\
macro(ArrayPush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
diff --git a/Source/JavaScriptCore/dfg/DFGOSREntry.cpp b/Source/JavaScriptCore/dfg/DFGOSREntry.cpp
index b838c4fb4..ed13ed5b5 100644
--- a/Source/JavaScriptCore/dfg/DFGOSREntry.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSREntry.cpp
@@ -44,7 +44,7 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn
ASSERT(!codeBlock->jitCodeMap());
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("OSR in %p(%p) from bc#%u\n", codeBlock, codeBlock->alternative(), bytecodeIndex);
+ dataLogF("OSR in %p(%p) from bc#%u\n", codeBlock, codeBlock->alternative(), bytecodeIndex);
#endif
JSGlobalData* globalData = &exec->globalData();
@@ -52,7 +52,7 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn
if (!entry) {
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog(" OSR failed because the entrypoint was optimized out.\n");
+ dataLogF(" OSR failed because the entrypoint was optimized out.\n");
#endif
return 0;
}
@@ -86,9 +86,9 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn
for (size_t argument = 0; argument < entry->m_expectedValues.numberOfArguments(); ++argument) {
if (argument >= exec->argumentCountIncludingThis()) {
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog(" OSR failed because argument %zu was not passed, expected ", argument);
+ dataLogF(" OSR failed because argument %zu was not passed, expected ", argument);
entry->m_expectedValues.argument(argument).dump(WTF::dataFile());
- dataLog(".\n");
+ dataLogF(".\n");
#endif
return 0;
}
@@ -101,9 +101,9 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn
if (!entry->m_expectedValues.argument(argument).validate(value)) {
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog(" OSR failed because argument %zu is %s, expected ", argument, value.description());
+ dataLogF(" OSR failed because argument %zu is %s, expected ", argument, value.description());
entry->m_expectedValues.argument(argument).dump(WTF::dataFile());
- dataLog(".\n");
+ dataLogF(".\n");
#endif
return 0;
}
@@ -113,7 +113,7 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn
if (entry->m_localsForcedDouble.get(local)) {
if (!exec->registers()[local].jsValue().isNumber()) {
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog(" OSR failed because variable %zu is %s, expected number.\n", local, exec->registers()[local].jsValue().description());
+ dataLogF(" OSR failed because variable %zu is %s, expected number.\n", local, exec->registers()[local].jsValue().description());
#endif
return 0;
}
@@ -121,9 +121,9 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn
}
if (!entry->m_expectedValues.local(local).validate(exec->registers()[local].jsValue())) {
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog(" OSR failed because variable %zu is %s, expected ", local, exec->registers()[local].jsValue().description());
+ dataLogF(" OSR failed because variable %zu is %s, expected ", local, exec->registers()[local].jsValue().description());
entry->m_expectedValues.local(local).dump(WTF::dataFile());
- dataLog(".\n");
+ dataLogF(".\n");
#endif
return 0;
}
@@ -138,13 +138,13 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn
if (!globalData->interpreter->stack().grow(&exec->registers()[codeBlock->m_numCalleeRegisters])) {
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog(" OSR failed because stack growth failed.\n");
+ dataLogF(" OSR failed because stack growth failed.\n");
#endif
return 0;
}
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog(" OSR should succeed.\n");
+ dataLogF(" OSR should succeed.\n");
#endif
// 3) Perform data format conversions.
@@ -162,7 +162,7 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn
void* result = codeBlock->getJITCode().executableAddressAtOffset(entry->m_machineCodeOffset);
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog(" OSR returning machine code address %p.\n", result);
+ dataLogF(" OSR returning machine code address %p.\n", result);
#endif
return result;
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
index 2ce1c887b..c65443e29 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
@@ -81,7 +81,7 @@ void compileOSRExit(ExecState* exec)
recovery = &codeBlock->speculationRecovery(exit.m_recoveryIndex - 1);
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Generating OSR exit #%u (seq#%u, bc#%u, @%u, %s) for code block %p.\n", exitIndex, exit.m_streamIndex, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, exitKindToString(exit.m_kind), codeBlock);
+ dataLogF("Generating OSR exit #%u (seq#%u, bc#%u, @%u, %s) for code block %p.\n", exitIndex, exit.m_streamIndex, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, exitKindToString(exit.m_kind), codeBlock);
#endif
{
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
index df4f3c905..732e67c30 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
@@ -37,14 +37,14 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
{
// 1) Pro-forma stuff.
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("OSR exit for Node @%d (", (int)exit.m_nodeIndex);
+ dataLogF("OSR exit for Node @%d (", (int)exit.m_nodeIndex);
for (CodeOrigin codeOrigin = exit.m_codeOrigin; ; codeOrigin = codeOrigin.inlineCallFrame->caller) {
- dataLog("bc#%u", codeOrigin.bytecodeIndex);
+ dataLogF("bc#%u", codeOrigin.bytecodeIndex);
if (!codeOrigin.inlineCallFrame)
break;
- dataLog(" -> %p ", codeOrigin.inlineCallFrame->executable.get());
+ dataLogF(" -> %p ", codeOrigin.inlineCallFrame->executable.get());
}
- dataLog(") at JIT offset 0x%x ", m_jit.debugOffset());
+ dataLogF(") at JIT offset 0x%x ", m_jit.debugOffset());
dumpOperands(operands, WTF::dataFile());
#endif
#if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE)
@@ -762,7 +762,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
m_jit.jump(GPRInfo::regT2);
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog(" -> %p\n", jumpTarget);
+ dataLogF(" -> %p\n", jumpTarget);
#endif
}
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
index b278997ab..b83c0b3f5 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
@@ -37,14 +37,14 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
{
// 1) Pro-forma stuff.
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("OSR exit for Node @%d (", (int)exit.m_nodeIndex);
+ dataLogF("OSR exit for Node @%d (", (int)exit.m_nodeIndex);
for (CodeOrigin codeOrigin = exit.m_codeOrigin; ; codeOrigin = codeOrigin.inlineCallFrame->caller) {
- dataLog("bc#%u", codeOrigin.bytecodeIndex);
+ dataLogF("bc#%u", codeOrigin.bytecodeIndex);
if (!codeOrigin.inlineCallFrame)
break;
- dataLog(" -> %p ", codeOrigin.inlineCallFrame->executable.get());
+ dataLogF(" -> %p ", codeOrigin.inlineCallFrame->executable.get());
}
- dataLog(") ");
+ dataLogF(") ");
dumpOperands(operands, WTF::dataFile());
#endif
#if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE)
@@ -138,7 +138,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
EncodedJSValue* bucket = exit.m_valueProfile.getSpecFailBucket(0);
#if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE)
- dataLog(" (have exit profile, bucket %p) ", bucket);
+ dataLogF(" (have exit profile, bucket %p) ", bucket);
#endif
if (exit.m_jsValueSource.isAddress()) {
@@ -243,24 +243,24 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
}
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog(" ");
+ dataLogF(" ");
if (numberOfPoisonedVirtualRegisters)
- dataLog("Poisoned=%u ", numberOfPoisonedVirtualRegisters);
+ dataLogF("Poisoned=%u ", numberOfPoisonedVirtualRegisters);
if (numberOfDisplacedVirtualRegisters)
- dataLog("Displaced=%u ", numberOfDisplacedVirtualRegisters);
+ dataLogF("Displaced=%u ", numberOfDisplacedVirtualRegisters);
if (haveUnboxedInt32s)
- dataLog("UnboxedInt32 ");
+ dataLogF("UnboxedInt32 ");
if (haveUnboxedDoubles)
- dataLog("UnboxedDoubles ");
+ dataLogF("UnboxedDoubles ");
if (haveUInt32s)
- dataLog("UInt32 ");
+ dataLogF("UInt32 ");
if (haveFPRs)
- dataLog("FPR ");
+ dataLogF("FPR ");
if (haveConstants)
- dataLog("Constants ");
+ dataLogF("Constants ");
if (haveUndefined)
- dataLog("Undefined ");
- dataLog(" ");
+ dataLogF("Undefined ");
+ dataLogF(" ");
#endif
ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(sizeof(EncodedJSValue) * std::max(haveUInt32s ? 2u : 0u, numberOfPoisonedVirtualRegisters + (numberOfDisplacedVirtualRegisters <= GPRInfo::numberOfRegisters ? 0 : numberOfDisplacedVirtualRegisters)));
@@ -710,7 +710,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
m_jit.jump(GPRInfo::regT1);
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("-> %p\n", jumpTarget);
+ dataLogF("-> %p\n", jumpTarget);
#endif
}
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 0e45e230c..909c657a1 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"
@@ -302,12 +302,12 @@ JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* constructor)
return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->cachedInheritorID(exec));
}
-JSCell* DFG_OPERATION operationNewObject(ExecState* exec)
+JSCell* DFG_OPERATION operationNewObject(ExecState* exec, Structure* structure)
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
- return constructEmptyObject(exec);
+ return constructEmptyObject(exec, structure);
}
EncodedJSValue DFG_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
@@ -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();
@@ -1019,14 +1062,14 @@ char* DFG_OPERATION operationLinkConstruct(ExecState* execCallee)
return linkFor(execCallee, CodeForConstruct);
}
-inline char* virtualFor(ExecState* execCallee, CodeSpecializationKind kind)
+inline char* virtualForWithFunction(ExecState* execCallee, CodeSpecializationKind kind, JSCell*& calleeAsFunctionCell)
{
ExecState* exec = execCallee->callerFrame();
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
JSValue calleeAsValue = execCallee->calleeAsValue();
- JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
+ calleeAsFunctionCell = getJSFunction(calleeAsValue);
if (UNLIKELY(!calleeAsFunctionCell))
return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind));
@@ -1044,6 +1087,56 @@ inline char* virtualFor(ExecState* execCallee, CodeSpecializationKind kind)
return reinterpret_cast<char*>(executable->generatedJITCodeWithArityCheckFor(kind).executableAddress());
}
+inline char* virtualFor(ExecState* execCallee, CodeSpecializationKind kind)
+{
+ JSCell* calleeAsFunctionCellIgnored;
+ return virtualForWithFunction(execCallee, kind, calleeAsFunctionCellIgnored);
+}
+
+static bool attemptToOptimizeClosureCall(ExecState* execCallee, JSCell* calleeAsFunctionCell, CallLinkInfo& callLinkInfo)
+{
+ if (!calleeAsFunctionCell)
+ return false;
+
+ JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell);
+ JSFunction* oldCallee = callLinkInfo.callee.get();
+
+ if (!oldCallee
+ || oldCallee->structure() != callee->structure()
+ || oldCallee->executable() != callee->executable())
+ return false;
+
+ ASSERT(callee->executable()->hasJITCodeForCall());
+ MacroAssemblerCodePtr codePtr = callee->executable()->generatedJITCodeForCall().addressForCall();
+
+ CodeBlock* codeBlock;
+ if (callee->executable()->isHostFunction())
+ codeBlock = 0;
+ else {
+ codeBlock = &jsCast<FunctionExecutable*>(callee->executable())->generatedBytecodeForCall();
+ if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()))
+ return false;
+ }
+
+ dfgLinkClosureCall(
+ execCallee, callLinkInfo, codeBlock,
+ callee->structure(), callee->executable(), codePtr);
+
+ return true;
+}
+
+char* DFG_OPERATION operationLinkClosureCall(ExecState* execCallee)
+{
+ JSCell* calleeAsFunctionCell;
+ char* result = virtualForWithFunction(execCallee, CodeForCall, calleeAsFunctionCell);
+ CallLinkInfo& callLinkInfo = execCallee->callerFrame()->codeBlock()->getCallLinkInfo(execCallee->returnPC());
+
+ if (!attemptToOptimizeClosureCall(execCallee, calleeAsFunctionCell, callLinkInfo))
+ dfgLinkSlowFor(execCallee, callLinkInfo, CodeForCall);
+
+ return result;
+}
+
char* DFG_OPERATION operationVirtualCall(ExecState* execCallee)
{
return virtualFor(execCallee, CodeForCall);
@@ -1327,30 +1420,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)
@@ -1423,7 +1522,7 @@ void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void*
SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw);
CodeBlock* codeBlock = debugInfo->codeBlock;
CodeBlock* alternative = codeBlock->alternative();
- dataLog("Speculation failure in %p at @%u with executeCounter = %s, "
+ dataLogF("Speculation failure in %p at @%u with executeCounter = %s, "
"reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, "
"osrExitCounter = %u\n",
codeBlock,
@@ -1438,7 +1537,7 @@ void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void*
extern "C" void DFG_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock)
{
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("%p: Entered reoptimize\n", codeBlock);
+ dataLogF("%p: Entered reoptimize\n", codeBlock);
#endif
// We must be called with the baseline code block.
ASSERT(JITCode::isBaselineCode(codeBlock->getJITType()));
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 8d2beacec..00e6b07b7 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*);
@@ -84,6 +85,7 @@ typedef JSCell* DFG_OPERATION (*C_DFGOperation_E)(ExecState*);
typedef JSCell* DFG_OPERATION (*C_DFGOperation_EC)(ExecState*, JSCell*);
typedef JSCell* DFG_OPERATION (*C_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef JSCell* DFG_OPERATION (*C_DFGOperation_EIcf)(ExecState*, InlineCallFrame*);
+typedef JSCell* DFG_OPERATION (*C_DFGOperation_ESt)(ExecState*, Structure*);
typedef double DFG_OPERATION (*D_DFGOperation_DD)(double, double);
typedef double DFG_OPERATION (*D_DFGOperation_ZZ)(int32_t, int32_t);
typedef double DFG_OPERATION (*D_DFGOperation_EJ)(ExecState*, EncodedJSValue);
@@ -92,6 +94,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*);
@@ -116,7 +119,7 @@ typedef char* DFG_OPERATION (*P_DFGOperation_EStSS)(ExecState*, Structure*, size
typedef char* DFG_OPERATION (*P_DFGOperation_EStZ)(ExecState*, Structure*, int32_t);
// These routines are provide callbacks out to C++ implementations of operations too complex to JIT.
-JSCell* DFG_OPERATION operationNewObject(ExecState*) WTF_INTERNAL;
+JSCell* DFG_OPERATION operationNewObject(ExecState*, Structure*) WTF_INTERNAL;
JSCell* DFG_OPERATION operationCreateThis(ExecState*, JSCell* constructor) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationConvertThis(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
@@ -148,7 +151,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;
@@ -175,6 +181,7 @@ size_t DFG_OPERATION operationCompareStrictEqCell(ExecState*, EncodedJSValue enc
size_t DFG_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
char* DFG_OPERATION operationVirtualCall(ExecState*) WTF_INTERNAL;
char* DFG_OPERATION operationLinkCall(ExecState*) WTF_INTERNAL;
+char* DFG_OPERATION operationLinkClosureCall(ExecState*) WTF_INTERNAL;
char* DFG_OPERATION operationVirtualConstruct(ExecState*) WTF_INTERNAL;
char* DFG_OPERATION operationLinkConstruct(ExecState*) WTF_INTERNAL;
JSCell* DFG_OPERATION operationCreateActivation(ExecState*) WTF_INTERNAL;
@@ -195,9 +202,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/DFGPhase.cpp b/Source/JavaScriptCore/dfg/DFGPhase.cpp
index f97c49e31..20301e814 100644
--- a/Source/JavaScriptCore/dfg/DFGPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPhase.cpp
@@ -35,8 +35,8 @@ namespace JSC { namespace DFG {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
void Phase::beginPhase()
{
- dataLog("Beginning DFG phase %s.\n", m_name);
- dataLog("Graph before %s:\n", m_name);
+ dataLogF("Beginning DFG phase %s.\n", m_name);
+ dataLogF("Graph before %s:\n", m_name);
m_graph.dump();
}
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGPhase.h b/Source/JavaScriptCore/dfg/DFGPhase.h
index a73d26baf..939e199e0 100644
--- a/Source/JavaScriptCore/dfg/DFGPhase.h
+++ b/Source/JavaScriptCore/dfg/DFGPhase.h
@@ -83,7 +83,7 @@ bool runAndLog(PhaseType& phase)
bool result = phase.run();
#if DFG_ENABLE(DEBUG_VERBOSE)
if (result)
- dataLog("Phase %s changed the IR.\n", phase.name());
+ dataLogF("Phase %s changed the IR.\n", phase.name());
#endif
return result;
}
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 3e8ead5c6..4b8a17285 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -116,6 +116,52 @@ private:
return false;
return !!m_graph.valueOfNumberConstant(nodeIndex);
}
+
+ bool isWithinPowerOfTwoForConstant(Node& node, int power)
+ {
+ JSValue immediateValue = node.valueOfJSConstant(codeBlock());
+ if (!immediateValue.isInt32())
+ return false;
+ int32_t intImmediate = immediateValue.asInt32();
+ return intImmediate > -(1 << power) && intImmediate < (1 << power);
+ }
+
+ bool isWithinPowerOfTwoNonRecursive(NodeIndex nodeIndex, int power)
+ {
+ Node& node = m_graph[nodeIndex];
+ if (node.op() != JSConstant)
+ return false;
+ return isWithinPowerOfTwoForConstant(node, power);
+ }
+
+ bool isWithinPowerOfTwo(NodeIndex nodeIndex, int power)
+ {
+ Node& node = m_graph[nodeIndex];
+ switch (node.op()) {
+ case JSConstant: {
+ return isWithinPowerOfTwoForConstant(node, power);
+ }
+
+ case BitAnd: {
+ return isWithinPowerOfTwoNonRecursive(node.child1().index(), power)
+ || isWithinPowerOfTwoNonRecursive(node.child2().index(), power);
+ }
+
+ case BitRShift:
+ case BitURShift: {
+ Node& shiftAmount = m_graph[node.child2()];
+ if (shiftAmount.op() != JSConstant)
+ return false;
+ JSValue immediateValue = shiftAmount.valueOfJSConstant(codeBlock());
+ if (!immediateValue.isInt32())
+ return false;
+ return immediateValue > 32 - power;
+ }
+
+ default:
+ return false;
+ }
+ }
SpeculatedType speculatedDoubleTypeForPrediction(SpeculatedType value)
{
@@ -140,7 +186,7 @@ private:
NodeFlags flags = node.flags() & NodeBackPropMask;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" %s @%u: %s ", Graph::opName(op), m_compileIndex, nodeFlagsAsString(flags));
+ dataLogF(" %s @%u: %s ", Graph::opName(op), m_compileIndex, nodeFlagsAsString(flags));
#endif
bool changed = false;
@@ -184,7 +230,7 @@ private:
case BitURShift: {
changed |= setPrediction(SpecInt32);
flags |= NodeUsedAsInt;
- flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
+ flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther);
changed |= m_graph[node.child1()].mergeFlags(flags);
changed |= m_graph[node.child2()].mergeFlags(flags);
break;
@@ -193,7 +239,7 @@ private:
case ValueToInt32: {
changed |= setPrediction(SpecInt32);
flags |= NodeUsedAsInt;
- flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
+ flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther);
changed |= m_graph[node.child1()].mergeFlags(flags);
break;
}
@@ -221,28 +267,10 @@ private:
case StringCharCodeAt: {
changed |= mergePrediction(SpecInt32);
changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
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 +286,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
@@ -272,6 +300,8 @@ private:
if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
flags &= ~NodeNeedsNegZero;
+ if (m_graph[node.child1()].hasNumberResult() || m_graph[node.child2()].hasNumberResult())
+ flags &= ~NodeUsedAsOther;
changed |= m_graph[node.child1()].mergeFlags(flags);
changed |= m_graph[node.child2()].mergeFlags(flags);
@@ -291,6 +321,7 @@ private:
if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
flags &= ~NodeNeedsNegZero;
+ flags &= ~NodeUsedAsOther;
changed |= m_graph[node.child1()].mergeFlags(flags);
changed |= m_graph[node.child2()].mergeFlags(flags);
@@ -310,6 +341,7 @@ private:
if (isNotZero(node.child1().index()) || isNotZero(node.child2().index()))
flags &= ~NodeNeedsNegZero;
+ flags &= ~NodeUsedAsOther;
changed |= m_graph[node.child1()].mergeFlags(flags);
changed |= m_graph[node.child2()].mergeFlags(flags);
@@ -324,6 +356,8 @@ private:
changed |= mergePrediction(speculatedDoubleTypeForPrediction(m_graph[node.child1()].prediction()));
}
+ flags &= ~NodeUsedAsOther;
+
changed |= m_graph[node.child1()].mergeFlags(flags);
break;
@@ -333,7 +367,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
@@ -341,6 +375,8 @@ private:
}
flags |= NodeUsedAsNumber;
+ flags &= ~NodeUsedAsOther;
+
changed |= m_graph[node.child1()].mergeFlags(flags);
changed |= m_graph[node.child2()].mergeFlags(flags);
break;
@@ -359,10 +395,20 @@ 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
- // no matter what, and always forces its inputs to check as well.
+ // can change the outcome. So, ArithMul always forces its inputs to
+ // check for overflow. Additionally, it will have to check for overflow
+ // itself unless we can prove that there is no way for the values
+ // produced to cause double rounding.
+
+ if (!isWithinPowerOfTwo(node.child1().index(), 22)
+ && !isWithinPowerOfTwo(node.child2().index(), 22))
+ flags |= NodeUsedAsNumber;
+
+ changed |= node.mergeFlags(flags);
flags |= NodeUsedAsNumber | NodeNeedsNegZero;
+ flags &= ~NodeUsedAsOther;
+
changed |= m_graph[node.child1()].mergeFlags(flags);
changed |= m_graph[node.child2()].mergeFlags(flags);
break;
@@ -373,7 +419,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,10 +428,32 @@ 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;
+ flags &= ~NodeUsedAsOther;
+
+ changed |= m_graph[node.child1()].mergeFlags(flags);
+ changed |= m_graph[node.child2()].mergeFlags(flags);
+ 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 |= NodeUsedAsNumber | NodeNeedsNegZero;
+ flags &= ~NodeUsedAsOther;
+
changed |= m_graph[node.child1()].mergeFlags(flags);
changed |= m_graph[node.child2()].mergeFlags(flags);
break;
@@ -393,18 +461,20 @@ private:
case ArithSqrt: {
changed |= setPrediction(SpecDouble);
- changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue);
+ flags |= NodeUsedAsNumber | NodeNeedsNegZero;
+ flags &= ~NodeUsedAsOther;
+ changed |= m_graph[node.child1()].mergeFlags(flags);
break;
}
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);
break;
}
@@ -447,13 +517,13 @@ private:
changed |= mergePrediction(node.getHeapPrediction());
changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
break;
}
case GetMyArgumentByValSafe: {
changed |= mergePrediction(node.getHeapPrediction());
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
break;
}
@@ -554,7 +624,7 @@ private:
case NewArrayWithSize: {
changed |= setPrediction(SpecArray);
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue | NodeUsedAsInt);
break;
}
@@ -571,7 +641,7 @@ private:
case StringCharAt: {
changed |= setPrediction(SpecString);
changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
break;
}
@@ -580,7 +650,7 @@ private:
for (unsigned childIdx = node.firstChild();
childIdx < node.firstChild() + node.numChildren();
++childIdx)
- changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsNumber);
+ changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther);
break;
}
@@ -636,16 +706,17 @@ private:
case PhantomArguments:
case CheckArray:
case Arrayify:
- case ArrayifyToStructure: {
+ case ArrayifyToStructure:
+ case Identity: {
// This node should never be visible at this stage of compilation. It is
// inserted by fixup(), which follows this phase.
- ASSERT_NOT_REACHED();
+ CRASH();
break;
}
case PutByVal:
changed |= m_graph[m_graph.varArgChild(node, 0)].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
changed |= m_graph[m_graph.varArgChild(node, 2)].mergeFlags(NodeUsedAsValue);
break;
@@ -690,6 +761,7 @@ private:
case CheckArgumentsNotCreated:
case GlobalVarWatchpoint:
case GarbageValue:
+ case InheritorIDWatchpoint:
changed |= mergeDefaultFlags(node);
break;
@@ -700,7 +772,7 @@ private:
break;
case LastNodeType:
- ASSERT_NOT_REACHED();
+ CRASH();
break;
#else
default:
@@ -710,7 +782,7 @@ private:
}
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("%s\n", speculationToString(m_graph[m_compileIndex].prediction()));
+ dataLogF("%s\n", speculationToString(m_graph[m_compileIndex].prediction()));
#endif
m_changed |= changed;
@@ -743,7 +815,7 @@ private:
void propagateForward()
{
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Propagating predictions forward [%u]\n", ++m_count);
+ dataLogF("Propagating predictions forward [%u]\n", ++m_count);
#endif
for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
propagate(m_graph[m_compileIndex]);
@@ -752,7 +824,7 @@ private:
void propagateBackward()
{
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Propagating predictions backward [%u]\n", ++m_count);
+ dataLogF("Propagating predictions backward [%u]\n", ++m_count);
#endif
for (m_compileIndex = m_graph.size(); m_compileIndex-- > 0;)
propagate(m_graph[m_compileIndex]);
@@ -761,7 +833,7 @@ private:
void doRoundOfDoubleVoting()
{
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Voting on double uses of locals [%u]\n", m_count);
+ dataLogF("Voting on double uses of locals [%u]\n", m_count);
#endif
for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i)
m_graph.m_variableAccessData[i].find()->clearVotes();
@@ -776,7 +848,7 @@ private:
DoubleBallot ballot;
- if (isNumberSpeculation(left) && isNumberSpeculation(right)
+ if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)
&& !m_graph.addShouldSpeculateInteger(node))
ballot = VoteDouble;
else
@@ -814,7 +886,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 +899,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 +921,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/DFGRegisterBank.h b/Source/JavaScriptCore/dfg/DFGRegisterBank.h
index 1d1d6fa52..3dbd1fe91 100644
--- a/Source/JavaScriptCore/dfg/DFGRegisterBank.h
+++ b/Source/JavaScriptCore/dfg/DFGRegisterBank.h
@@ -75,7 +75,6 @@ class RegisterBank {
public:
RegisterBank()
- : m_lastAllocated(NUM_REGS - 1)
{
}
@@ -86,12 +85,7 @@ public:
{
VirtualRegister ignored;
- for (uint32_t i = m_lastAllocated + 1; i < NUM_REGS; ++i) {
- if (!m_data[i].lockCount && m_data[i].name == InvalidVirtualRegister)
- return allocateInternal(i, ignored);
- }
- // Loop over the remaining entries.
- for (uint32_t i = 0; i <= m_lastAllocated; ++i) {
+ for (uint32_t i = 0; i < NUM_REGS; ++i) {
if (!m_data[i].lockCount && m_data[i].name == InvalidVirtualRegister)
return allocateInternal(i, ignored);
}
@@ -115,9 +109,6 @@ public:
uint32_t currentLowest = NUM_REGS;
SpillHint currentSpillOrder = SpillHintInvalid;
- // Scan through all register, starting at the last allocated & looping around.
- ASSERT(m_lastAllocated < NUM_REGS);
-
// This loop is broken into two halves, looping from the last allocated
// register (the register returned last time this method was called) to
// the maximum register value, then from 0 to the last allocated.
@@ -125,7 +116,7 @@ public:
// thrash, and minimize time spent scanning locked registers in allocation.
// If a unlocked and unnamed register is found return it immediately.
// Otherwise, find the first unlocked register with the lowest spillOrder.
- for (uint32_t i = m_lastAllocated + 1; i < NUM_REGS; ++i) {
+ for (uint32_t i = 0 ; i < NUM_REGS; ++i) {
// (1) If the current register is locked, it is not a candidate.
if (m_data[i].lockCount)
continue;
@@ -140,18 +131,6 @@ public:
currentLowest = i;
}
}
- // Loop over the remaining entries.
- for (uint32_t i = 0; i <= m_lastAllocated; ++i) {
- if (m_data[i].lockCount)
- continue;
- SpillHint spillOrder = m_data[i].spillOrder;
- if (spillOrder == SpillHintInvalid)
- return allocateInternal(i, spillMe);
- if (spillOrder < currentSpillOrder) {
- currentSpillOrder = spillOrder;
- currentLowest = i;
- }
- }
// Deadlock check - this could only occur is all registers are locked!
ASSERT(currentLowest != NUM_REGS && currentSpillOrder != SpillHintInvalid);
@@ -237,11 +216,11 @@ public:
// For each register, print the VirtualRegister 'name'.
for (uint32_t i =0; i < NUM_REGS; ++i) {
if (m_data[i].name != InvalidVirtualRegister)
- dataLog("[%02d]", m_data[i].name);
+ dataLogF("[%02d]", m_data[i].name);
else
- dataLog("[--]");
+ dataLogF("[--]");
}
- dataLog("\n");
+ dataLogF("\n");
}
#endif
@@ -354,7 +333,6 @@ private:
// Mark the register as locked (with a lock count of 1).
m_data[i].lockCount = 1;
- m_lastAllocated = i;
return BankInfo::toRegister(i);
}
@@ -378,8 +356,6 @@ private:
// Holds the current status of all registers.
MapEntry m_data[NUM_REGS];
- // Used to to implement a simple round-robin like allocation scheme.
- uint32_t m_lastAllocated;
};
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
index 7c15ef33e..a20eb544a 100644
--- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp
+++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
@@ -114,6 +114,23 @@ static void addStructureTransitionCheck(
failureCases, scratchGPR);
}
+static void replaceWithJump(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo, const MacroAssemblerCodePtr target)
+{
+ if (MacroAssembler::canJumpReplacePatchableBranchPtrWithPatch()) {
+ repatchBuffer.replaceWithJump(
+ RepatchBuffer::startOfPatchableBranchPtrWithPatchOnAddress(
+ stubInfo.callReturnLocation.dataLabelPtrAtOffset(
+ -(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall)),
+ CodeLocationLabel(target));
+ return;
+ }
+
+ repatchBuffer.relink(
+ stubInfo.callReturnLocation.jumpAtOffset(
+ stubInfo.patch.dfg.deltaCallToStructCheck),
+ CodeLocationLabel(target));
+}
+
static void emitRestoreScratch(MacroAssembler& stubJit, bool needToRestoreScratch, GPRReg scratchGPR, MacroAssembler::Jump& success, MacroAssembler::Jump& fail, MacroAssembler::JumpList failureCases)
{
if (needToRestoreScratch) {
@@ -284,7 +301,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
stubInfo.patch.dfg.deltaCallToDone).executableAddress()));
RepatchBuffer repatchBuffer(codeBlock);
- repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code()));
+ replaceWithJump(repatchBuffer, stubInfo, stubInfo.stubRoutine->code().code());
repatchBuffer.relink(stubInfo.callReturnLocation, operationGetById);
return true;
@@ -334,7 +351,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToSlowCase), stubInfo.stubRoutine);
RepatchBuffer repatchBuffer(codeBlock);
- repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code()));
+ replaceWithJump(repatchBuffer, stubInfo, stubInfo.stubRoutine->code().code());
repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdProtoBuildList);
stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain, count, true);
@@ -518,9 +535,11 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, isDirect);
- CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck);
RepatchBuffer repatchBuffer(codeBlock);
- repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine->code().code()));
+ repatchBuffer.relink(
+ stubInfo.callReturnLocation.jumpAtOffset(
+ stubInfo.patch.dfg.deltaCallToStructCheck),
+ CodeLocationLabel(stubRoutine->code().code()));
if (listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1))
return true;
@@ -584,9 +603,8 @@ static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const I
polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, true);
- CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck);
RepatchBuffer repatchBuffer(codeBlock);
- repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine->code().code()));
+ replaceWithJump(repatchBuffer, stubInfo, stubRoutine->code().code());
if (listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1))
return true;
@@ -976,7 +994,10 @@ static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier
stubInfo.stubRoutine);
RepatchBuffer repatchBuffer(codeBlock);
- repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code()));
+ repatchBuffer.relink(
+ stubInfo.callReturnLocation.jumpAtOffset(
+ stubInfo.patch.dfg.deltaCallToStructCheck),
+ CodeLocationLabel(stubInfo.stubRoutine->code().code()));
repatchBuffer.relink(stubInfo.callReturnLocation, appropriateListBuildingPutByIdFunction(slot, putKind));
stubInfo.initPutByIdTransition(*globalData, codeBlock->ownerExecutable(), oldStructure, structure, prototypeChain, putKind == Direct);
@@ -1092,8 +1113,20 @@ void dfgBuildPutByIdList(ExecState* exec, JSValue baseValue, const Identifier& p
dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind));
}
+static void linkSlowFor(RepatchBuffer& repatchBuffer, JSGlobalData* globalData, CallLinkInfo& callLinkInfo, CodeSpecializationKind kind)
+{
+ if (kind == CodeForCall) {
+ repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualCallThunkGenerator).code());
+ return;
+ }
+ ASSERT(kind == CodeForConstruct);
+ repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualConstructThunkGenerator).code());
+}
+
void dfgLinkFor(ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCodeBlock, JSFunction* callee, MacroAssemblerCodePtr codePtr, CodeSpecializationKind kind)
{
+ ASSERT(!callLinkInfo.stub);
+
CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock();
JSGlobalData* globalData = callerCodeBlock->globalData();
@@ -1108,17 +1141,125 @@ void dfgLinkFor(ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCo
calleeCodeBlock->linkIncomingCall(&callLinkInfo);
if (kind == CodeForCall) {
- repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualCallThunkGenerator).code());
+ repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(linkClosureCallThunkGenerator).code());
return;
}
+
ASSERT(kind == CodeForConstruct);
- repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualConstructThunkGenerator).code());
+ linkSlowFor(repatchBuffer, globalData, callLinkInfo, CodeForConstruct);
+}
+
+void dfgLinkSlowFor(ExecState* exec, CallLinkInfo& callLinkInfo, CodeSpecializationKind kind)
+{
+ CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock();
+ JSGlobalData* globalData = callerCodeBlock->globalData();
+
+ RepatchBuffer repatchBuffer(callerCodeBlock);
+
+ linkSlowFor(repatchBuffer, globalData, callLinkInfo, kind);
+}
+
+void dfgLinkClosureCall(ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCodeBlock, Structure* structure, ExecutableBase* executable, MacroAssemblerCodePtr codePtr)
+{
+ ASSERT(!callLinkInfo.stub);
+
+ CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock();
+ JSGlobalData* globalData = callerCodeBlock->globalData();
+
+ GPRReg calleeGPR = static_cast<GPRReg>(callLinkInfo.calleeGPR);
+
+ CCallHelpers stubJit(globalData, callerCodeBlock);
+
+ CCallHelpers::JumpList slowPath;
+
+#if USE(JSVALUE64)
+ slowPath.append(
+ stubJit.branchTest64(
+ CCallHelpers::NonZero, calleeGPR, GPRInfo::tagMaskRegister));
+#else
+ // We would have already checked that the callee is a cell.
+#endif
+
+ slowPath.append(
+ stubJit.branchPtr(
+ CCallHelpers::NotEqual,
+ CCallHelpers::Address(calleeGPR, JSCell::structureOffset()),
+ CCallHelpers::TrustedImmPtr(structure)));
+
+ slowPath.append(
+ stubJit.branchPtr(
+ CCallHelpers::NotEqual,
+ CCallHelpers::Address(calleeGPR, JSFunction::offsetOfExecutable()),
+ CCallHelpers::TrustedImmPtr(executable)));
+
+ stubJit.loadPtr(
+ CCallHelpers::Address(calleeGPR, JSFunction::offsetOfScopeChain()),
+ GPRInfo::returnValueGPR);
+
+#if USE(JSVALUE64)
+ stubJit.store64(
+ GPRInfo::returnValueGPR,
+ CCallHelpers::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register) * JSStack::ScopeChain)));
+#else
+ stubJit.storePtr(
+ GPRInfo::returnValueGPR,
+ CCallHelpers::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register) * JSStack::ScopeChain) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ stubJit.store32(
+ CCallHelpers::TrustedImm32(JSValue::CellTag),
+ CCallHelpers::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register) * JSStack::ScopeChain) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+#endif
+
+ JITCompiler::Call call = stubJit.nearCall();
+ JITCompiler::Jump done = stubJit.jump();
+
+ slowPath.link(&stubJit);
+ stubJit.move(CCallHelpers::TrustedImmPtr(callLinkInfo.callReturnLocation.executableAddress()), GPRInfo::nonArgGPR2);
+ stubJit.restoreReturnAddressBeforeReturn(GPRInfo::nonArgGPR2);
+ stubJit.move(calleeGPR, GPRInfo::nonArgGPR0);
+#if USE(JSVALUE32_64)
+ stubJit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), GPRInfo::nonArgGPR1);
+#endif
+ JITCompiler::Jump slow = stubJit.jump();
+
+ LinkBuffer patchBuffer(*globalData, &stubJit, callerCodeBlock);
+
+ patchBuffer.link(call, FunctionPtr(codePtr.executableAddress()));
+ patchBuffer.link(done, callLinkInfo.callReturnLocation.labelAtOffset(0));
+ patchBuffer.link(slow, CodeLocationLabel(globalData->getCTIStub(virtualCallThunkGenerator).code()));
+
+ RefPtr<ClosureCallStubRoutine> stubRoutine = adoptRef(new ClosureCallStubRoutine(
+ FINALIZE_DFG_CODE(
+ patchBuffer,
+ ("DFG closure call stub for CodeBlock %p, return point %p, target %p (CodeBlock %p)",
+ callerCodeBlock, callLinkInfo.callReturnLocation.labelAtOffset(0).executableAddress(),
+ codePtr.executableAddress(), calleeCodeBlock)),
+ *globalData, callerCodeBlock->ownerExecutable(), structure, executable, callLinkInfo.codeOrigin));
+
+ RepatchBuffer repatchBuffer(callerCodeBlock);
+
+ repatchBuffer.replaceWithJump(
+ RepatchBuffer::startOfBranchPtrWithPatchOnRegister(callLinkInfo.hotPathBegin),
+ CodeLocationLabel(stubRoutine->code().code()));
+ linkSlowFor(repatchBuffer, globalData, callLinkInfo, CodeForCall);
+
+ callLinkInfo.stub = stubRoutine.release();
+
+ ASSERT(!calleeCodeBlock || calleeCodeBlock->isIncomingCallAlreadyLinked(&callLinkInfo));
}
void dfgResetGetByID(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo)
{
repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdOptimize);
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), reinterpret_cast<void*>(-1));
+ CodeLocationDataLabelPtr structureLabel = stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall);
+ if (MacroAssembler::canJumpReplacePatchableBranchPtrWithPatch()) {
+ repatchBuffer.revertJumpReplacementToPatchableBranchPtrWithPatch(
+ RepatchBuffer::startOfPatchableBranchPtrWithPatchOnAddress(structureLabel),
+ MacroAssembler::Address(
+ static_cast<MacroAssembler::RegisterID>(stubInfo.patch.dfg.baseGPR),
+ JSCell::structureOffset()),
+ reinterpret_cast<void*>(-1));
+ }
+ repatchBuffer.repatch(structureLabel, reinterpret_cast<void*>(-1));
#if USE(JSVALUE64)
repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), 0);
#else
@@ -1143,7 +1284,16 @@ void dfgResetPutByID(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo)
optimizedFunction = operationPutByIdDirectNonStrictOptimize;
}
repatchBuffer.relink(stubInfo.callReturnLocation, optimizedFunction);
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), reinterpret_cast<void*>(-1));
+ CodeLocationDataLabelPtr structureLabel = stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall);
+ if (MacroAssembler::canJumpReplacePatchableBranchPtrWithPatch()) {
+ repatchBuffer.revertJumpReplacementToPatchableBranchPtrWithPatch(
+ RepatchBuffer::startOfPatchableBranchPtrWithPatchOnAddress(structureLabel),
+ MacroAssembler::Address(
+ static_cast<MacroAssembler::RegisterID>(stubInfo.patch.dfg.baseGPR),
+ JSCell::structureOffset()),
+ reinterpret_cast<void*>(-1));
+ }
+ repatchBuffer.repatch(structureLabel, reinterpret_cast<void*>(-1));
#if USE(JSVALUE64)
repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), 0);
#else
diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.h b/Source/JavaScriptCore/dfg/DFGRepatch.h
index 83d4e976d..97d26aab2 100644
--- a/Source/JavaScriptCore/dfg/DFGRepatch.h
+++ b/Source/JavaScriptCore/dfg/DFGRepatch.h
@@ -41,6 +41,8 @@ void dfgBuildGetByIDProtoList(ExecState*, JSValue, const Identifier&, const Prop
void dfgRepatchPutByID(ExecState*, JSValue, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
void dfgBuildPutByIdList(ExecState*, JSValue, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
void dfgLinkFor(ExecState*, CallLinkInfo&, CodeBlock*, JSFunction* callee, MacroAssemblerCodePtr, CodeSpecializationKind);
+void dfgLinkSlowFor(ExecState*, CallLinkInfo&, CodeSpecializationKind);
+void dfgLinkClosureCall(ExecState*, CallLinkInfo&, CodeBlock*, Structure*, ExecutableBase*, MacroAssemblerCodePtr);
void dfgResetGetByID(RepatchBuffer&, StructureStubInfo&);
void dfgResetPutByID(RepatchBuffer&, StructureStubInfo&);
diff --git a/Source/JavaScriptCore/dfg/DFGScoreBoard.h b/Source/JavaScriptCore/dfg/DFGScoreBoard.h
index 430bdf552..9b509fe2a 100644
--- a/Source/JavaScriptCore/dfg/DFGScoreBoard.h
+++ b/Source/JavaScriptCore/dfg/DFGScoreBoard.h
@@ -113,7 +113,7 @@ public:
ASSERT(m_used[index] != max());
if (node.refCount() == ++m_used[index]) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Freeing virtual register %u.", index);
+ dataLogF(" Freeing virtual register %u.", index);
#endif
// If the use count in the scoreboard reaches the use count for the node,
// then this was its last use; the virtual register is now free.
@@ -122,7 +122,7 @@ public:
m_free.append(index);
} else {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Virtual register %u is at %u/%u uses.", index, m_used[index], node.refCount());
+ dataLogF(" Virtual register %u is at %u/%u uses.", index, m_used[index], node.refCount());
#endif
}
}
@@ -148,26 +148,26 @@ public:
#ifndef NDEBUG
void dump()
{
- dataLog(" USED: [ ");
+ dataLogF(" USED: [ ");
for (unsigned i = 0; i < m_used.size(); ++i) {
if (!m_free.contains(i)) {
- dataLog("%d:", i);
+ dataLogF("%d:", i);
if (m_used[i] == max())
- dataLog("local ");
+ dataLogF("local ");
else
- dataLog("%d ", m_used[i]);
+ dataLogF("%d ", m_used[i]);
}
}
- dataLog("]\n");
+ dataLogF("]\n");
- dataLog(" FREE: [ ");
+ dataLogF(" FREE: [ ");
for (unsigned i = 0; i < m_used.size(); ++i) {
if (m_free.contains(i) && m_used[i] != max()) {
ASSERT(!m_used[i]);
- dataLog("%d ", i);
+ dataLogF("%d ", i);
}
}
- dataLog("]\n");
+ dataLogF("]\n");
}
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGSlowPathGenerator.h b/Source/JavaScriptCore/dfg/DFGSlowPathGenerator.h
index fa1f888e0..4acd8690a 100644
--- a/Source/JavaScriptCore/dfg/DFGSlowPathGenerator.h
+++ b/Source/JavaScriptCore/dfg/DFGSlowPathGenerator.h
@@ -49,7 +49,7 @@ public:
void generate(SpeculativeJIT* jit)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Generating slow path %p at offset 0x%x\n", this, jit->m_jit.debugOffset());
+ dataLogF("Generating slow path %p at offset 0x%x\n", this, jit->m_jit.debugOffset());
#endif
m_label = jit->m_jit.label();
jit->m_compileIndex = m_compileIndex;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 6bedd6d68..41276d233 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. :-/
@@ -258,7 +274,7 @@ void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs js
{
ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpeculativeJIT was terminated.\n");
+ dataLogF("SpeculativeJIT was terminated.\n");
#endif
if (!m_compileOkay)
return;
@@ -276,7 +292,7 @@ void SpeculativeJIT::terminateSpeculativeExecutionWithConditionalDirection(ExitK
{
ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpeculativeJIT was terminated.\n");
+ dataLogF("SpeculativeJIT was terminated.\n");
#endif
if (!m_compileOkay)
return;
@@ -292,7 +308,7 @@ void SpeculativeJIT::addSlowPathGenerator(PassOwnPtr<SlowPathGenerator> slowPath
void SpeculativeJIT::runSlowPathGenerators()
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Running %lu slow path generators.\n", m_slowPathGenerators.size());
+ dataLogF("Running %lu slow path generators.\n", m_slowPathGenerators.size());
#endif
for (unsigned i = 0; i < m_slowPathGenerators.size(); ++i)
m_slowPathGenerators[i]->generate(this);
@@ -343,32 +359,49 @@ const TypedArrayDescriptor* SpeculativeJIT::typedArrayDescriptor(ArrayMode array
}
}
+JITCompiler::Jump SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode, IndexingType shape, bool invert)
+{
+ switch (arrayMode.arrayClass()) {
+ case Array::OriginalArray: {
+ CRASH();
+ JITCompiler::Jump result; // I already know that VC++ takes unkindly to the expression "return Jump()", so I'm doing it this way in anticipation of someone eventually using VC++ to compile the DFG.
+ return result;
+ }
+
+ case Array::Array:
+ m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR);
+ return m_jit.branch32(
+ invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | shape));
+
+ default:
+ 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: {
+ ASSERT(!arrayMode.isJSArrayWithOriginalStructure());
+
if (arrayMode.isJSArray()) {
if (arrayMode.isSlowPut()) {
if (invert) {
- JITCompiler::Jump slow =
- m_jit.branchTest32(
- MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(IsArray));
+ JITCompiler::Jump slow = m_jit.branchTest32(
+ MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(IsArray));
m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
m_jit.sub32(TrustedImm32(ArrayStorageShape), tempGPR);
result.append(
@@ -426,7 +459,7 @@ void SpeculativeJIT::checkArray(Node& node)
const TypedArrayDescriptor* result = typedArrayDescriptor(node.arrayMode());
- if (node.arrayMode().alreadyChecked(m_state.forNode(node.child1()))) {
+ if (node.arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1()))) {
noResult(m_compileIndex);
return;
}
@@ -437,6 +470,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 +563,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;
@@ -956,33 +1005,33 @@ static const char* dataFormatString(DataFormat format)
void SpeculativeJIT::dump(const char* label)
{
if (label)
- dataLog("<%s>\n", label);
+ dataLogF("<%s>\n", label);
- dataLog(" gprs:\n");
+ dataLogF(" gprs:\n");
m_gprs.dump();
- dataLog(" fprs:\n");
+ dataLogF(" fprs:\n");
m_fprs.dump();
- dataLog(" VirtualRegisters:\n");
+ dataLogF(" VirtualRegisters:\n");
for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
GenerationInfo& info = m_generationInfo[i];
if (info.alive())
- dataLog(" % 3d:%s%s", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat()));
+ dataLogF(" % 3d:%s%s", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat()));
else
- dataLog(" % 3d:[__][__]", i);
+ dataLogF(" % 3d:[__][__]", i);
if (info.registerFormat() == DataFormatDouble)
- dataLog(":fpr%d\n", info.fpr());
+ dataLogF(":fpr%d\n", info.fpr());
else if (info.registerFormat() != DataFormatNone
#if USE(JSVALUE32_64)
&& !(info.registerFormat() & DataFormatJS)
#endif
) {
ASSERT(info.gpr() != InvalidGPRReg);
- dataLog(":%s\n", GPRInfo::debugName(info.gpr()));
+ dataLogF(":%s\n", GPRInfo::debugName(info.gpr()));
} else
- dataLog("\n");
+ dataLogF("\n");
}
if (label)
- dataLog("</%s>\n", label);
+ dataLogF("</%s>\n", label);
}
#endif
@@ -994,13 +1043,13 @@ void SpeculativeJIT::checkConsistency()
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.isLocked()) {
- dataLog("DFG_CONSISTENCY_CHECK failed: gpr %s is locked.\n", iter.debugName());
+ dataLogF("DFG_CONSISTENCY_CHECK failed: gpr %s is locked.\n", iter.debugName());
failed = true;
}
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
if (iter.isLocked()) {
- dataLog("DFG_CONSISTENCY_CHECK failed: fpr %s is locked.\n", iter.debugName());
+ dataLogF("DFG_CONSISTENCY_CHECK failed: fpr %s is locked.\n", iter.debugName());
failed = true;
}
}
@@ -1028,7 +1077,7 @@ void SpeculativeJIT::checkConsistency()
GPRReg gpr = info.gpr();
ASSERT(gpr != InvalidGPRReg);
if (m_gprs.name(gpr) != virtualRegister) {
- dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (gpr %s).\n", virtualRegister, GPRInfo::debugName(gpr));
+ dataLogF("DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (gpr %s).\n", virtualRegister, GPRInfo::debugName(gpr));
failed = true;
}
break;
@@ -1037,7 +1086,7 @@ void SpeculativeJIT::checkConsistency()
FPRReg fpr = info.fpr();
ASSERT(fpr != InvalidFPRReg);
if (m_fprs.name(fpr) != virtualRegister) {
- dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (fpr %s).\n", virtualRegister, FPRInfo::debugName(fpr));
+ dataLogF("DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (fpr %s).\n", virtualRegister, FPRInfo::debugName(fpr));
failed = true;
}
break;
@@ -1053,18 +1102,18 @@ void SpeculativeJIT::checkConsistency()
GenerationInfo& info = m_generationInfo[virtualRegister];
#if USE(JSVALUE64)
if (iter.regID() != info.gpr()) {
- dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
+ dataLogF("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
failed = true;
}
#else
if (!(info.registerFormat() & DataFormatJS)) {
if (iter.regID() != info.gpr()) {
- dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
+ dataLogF("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
failed = true;
}
} else {
if (iter.regID() != info.tagGPR() && iter.regID() != info.payloadGPR()) {
- dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
+ dataLogF("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
failed = true;
}
}
@@ -1078,7 +1127,7 @@ void SpeculativeJIT::checkConsistency()
GenerationInfo& info = m_generationInfo[virtualRegister];
if (iter.regID() != info.fpr()) {
- dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for fpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
+ dataLogF("DFG_CONSISTENCY_CHECK failed: name mismatch for fpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
failed = true;
}
}
@@ -1496,7 +1545,7 @@ void SpeculativeJIT::compile(BasicBlock& block)
#endif
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Setting up state for block #%u: ", m_block);
+ dataLogF("Setting up state for block #%u: ", m_block);
#endif
m_stream->appendAndLog(VariableEvent::reset());
@@ -1544,7 +1593,7 @@ void SpeculativeJIT::compile(BasicBlock& block)
}
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("\n");
+ dataLogF("\n");
#endif
for (m_indexInBlock = 0; m_indexInBlock < block.size(); ++m_indexInBlock) {
@@ -1554,7 +1603,7 @@ void SpeculativeJIT::compile(BasicBlock& block)
m_codeOriginForOSR = node.codeOrigin;
if (!node.shouldGenerate()) {
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpeculativeJIT skipping Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
+ dataLogF("SpeculativeJIT skipping Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
#endif
switch (node.op()) {
case JSConstant:
@@ -1601,7 +1650,7 @@ void SpeculativeJIT::compile(BasicBlock& block)
// The exception is the this argument, which we don't really need to be
// able to recover.
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("\nRecovery for argument %d: ", i);
+ dataLogF("\nRecovery for argument %d: ", i);
recovery.dump(WTF::dataFile());
#endif
inlineCallFrame->arguments[i] = recovery;
@@ -1617,7 +1666,7 @@ void SpeculativeJIT::compile(BasicBlock& block)
} else {
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
+ dataLogF("SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
#endif
#if DFG_ENABLE(JIT_BREAK_ON_EVERY_NODE)
m_jit.breakpoint();
@@ -1642,25 +1691,25 @@ void SpeculativeJIT::compile(BasicBlock& block)
#if DFG_ENABLE(DEBUG_VERBOSE)
if (node.hasResult()) {
GenerationInfo& info = m_generationInfo[node.virtualRegister()];
- dataLog("-> %s, vr#%d", dataFormatToString(info.registerFormat()), (int)node.virtualRegister());
+ dataLogF("-> %s, vr#%d", dataFormatToString(info.registerFormat()), (int)node.virtualRegister());
if (info.registerFormat() != DataFormatNone) {
if (info.registerFormat() == DataFormatDouble)
- dataLog(", %s", FPRInfo::debugName(info.fpr()));
+ dataLogF(", %s", FPRInfo::debugName(info.fpr()));
#if USE(JSVALUE32_64)
else if (info.registerFormat() & DataFormatJS)
- dataLog(", %s %s", GPRInfo::debugName(info.tagGPR()), GPRInfo::debugName(info.payloadGPR()));
+ dataLogF(", %s %s", GPRInfo::debugName(info.tagGPR()), GPRInfo::debugName(info.payloadGPR()));
#endif
else
- dataLog(", %s", GPRInfo::debugName(info.gpr()));
+ dataLogF(", %s", GPRInfo::debugName(info.gpr()));
}
- dataLog(" ");
+ dataLogF(" ");
} else
- dataLog(" ");
+ dataLogF(" ");
#endif
}
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("\n");
+ dataLogF("\n");
#endif
// Make sure that the abstract state is rematerialized for the next node.
@@ -1797,6 +1846,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());
@@ -1841,7 +1969,7 @@ void SpeculativeJIT::compileGetByValOnString(Node& node)
GPRReg propertyReg = property.gpr();
GPRReg storageReg = storage.gpr();
- ASSERT(ArrayMode(Array::String).alreadyChecked(m_state.forNode(node.child1())));
+ ASSERT(ArrayMode(Array::String).alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1())));
// unsigned comparison so we can filter out negative indices and indices that are too large
speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSString::offsetOfLength())));
@@ -1878,7 +2006,7 @@ void SpeculativeJIT::compileGetByValOnString(Node& node)
GeneratedOperandType SpeculativeJIT::checkGeneratedTypeForToInt32(NodeIndex nodeIndex)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("checkGeneratedTypeForToInt32@%d ", nodeIndex);
+ dataLogF("checkGeneratedTypeForToInt32@%d ", nodeIndex);
#endif
Node& node = at(nodeIndex);
VirtualRegister virtualRegister = node.virtualRegister();
@@ -2250,7 +2378,7 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor&
GPRTemporary result(this);
GPRReg resultReg = result.gpr();
- ASSERT(node.arrayMode().alreadyChecked(m_state.forNode(node.child1())));
+ ASSERT(node.arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1())));
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
@@ -2400,7 +2528,7 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor
GPRReg propertyReg = property.gpr();
GPRReg storageReg = storage.gpr();
- ASSERT(node.arrayMode().alreadyChecked(m_state.forNode(node.child1())));
+ ASSERT(node.arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1())));
FPRTemporary result(this);
FPRReg resultReg = result.fpr();
@@ -2437,7 +2565,7 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescripto
SpeculateDoubleOperand valueOp(this, valueUse);
- ASSERT_UNUSED(baseUse, node.arrayMode().alreadyChecked(m_state.forNode(baseUse)));
+ ASSERT_UNUSED(baseUse, node.arrayMode().alreadyChecked(m_jit.graph(), m_jit.graph()[m_compileIndex], m_state.forNode(baseUse)));
GPRTemporary result(this);
@@ -2763,7 +2891,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 +3129,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;
@@ -3260,7 +3388,7 @@ void SpeculativeJIT::compileGetByValOnArguments(Node& node)
if (!m_compileOkay)
return;
- ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_state.forNode(node.child1())));
+ ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1())));
// Two really lame checks.
speculationCheck(
@@ -3317,7 +3445,7 @@ void SpeculativeJIT::compileGetArgumentsLength(Node& node)
if (!m_compileOkay)
return;
- ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_state.forNode(node.child1())));
+ ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1())));
speculationCheck(
Uncountable, JSValueSource(), NoNode,
@@ -3336,6 +3464,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..f1384e269 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);
@@ -1363,6 +1368,11 @@ public:
m_jit.setupArgumentsWithExecState(TrustedImmPtr(inlineCallFrame));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_DFGOperation_ESt operation, GPRReg result, Structure* structure)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(S_DFGOperation_J operation, GPRReg result, GPRReg arg1)
{
m_jit.setupArguments(arg1);
@@ -1453,6 +1463,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 +1676,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);
@@ -1716,6 +1741,11 @@ public:
m_jit.setupArgumentsWithExecState(TrustedImmPtr(inlineCallFrame));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_DFGOperation_ESt operation, GPRReg result, Structure* structure)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(S_DFGOperation_J operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload)
{
m_jit.setupArguments(arg1Payload, arg1Tag);
@@ -1819,11 +1849,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 +2310,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 +2460,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 +3001,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 +3086,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..05af6962e 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -29,9 +29,11 @@
#if ENABLE(DFG_JIT)
+#include "ArrayPrototype.h"
#include "DFGCallArrayAllocatorSlowPathGenerator.h"
#include "DFGSlowPathGenerator.h"
#include "JSActivation.h"
+#include "ObjectPrototype.h"
namespace JSC { namespace DFG {
@@ -996,7 +998,6 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node& node, bool invert)
void SpeculativeJIT::emitCall(Node& node)
{
-
if (node.op() != Call)
ASSERT(node.op() == Construct);
@@ -1047,8 +1048,8 @@ void SpeculativeJIT::emitCall(Node& node)
m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
- slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, calleeTagGPR, TrustedImm32(JSValue::CellTag)));
+ slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
m_jit.loadPtr(MacroAssembler::Address(calleePayloadGPR, OBJECT_OFFSETOF(JSFunction, m_scope)), resultPayloadGPR);
m_jit.storePtr(resultPayloadGPR, MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * JSStack::ScopeChain + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * JSStack::ScopeChain + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
@@ -1082,14 +1083,14 @@ void SpeculativeJIT::emitCall(Node& node)
jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, DataFormatJS, UseChildrenCalledExplicitly);
- m_jit.addJSCall(fastCall, slowCall, targetToCheck, callType, at(m_compileIndex).codeOrigin);
+ m_jit.addJSCall(fastCall, slowCall, targetToCheck, callType, calleePayloadGPR, at(m_compileIndex).codeOrigin);
}
template<bool strict>
GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpecInt@%d ", nodeIndex);
+ dataLogF("SpecInt@%d ", nodeIndex);
#endif
if (isKnownNotInteger(nodeIndex)) {
terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
@@ -1187,7 +1188,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex)
FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpecDouble@%d ", nodeIndex);
+ dataLogF("SpecDouble@%d ", nodeIndex);
#endif
if (isKnownNotNumber(nodeIndex)) {
terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
@@ -1322,7 +1323,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpeculation)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpecCell@%d ", nodeIndex);
+ dataLogF("SpecCell@%d ", nodeIndex);
#endif
if (isKnownNotCell(nodeIndex)) {
terminateSpeculativeExecutionWithConditionalDirection(Uncountable, JSValueRegs(), NoNode, isForwardSpeculation);
@@ -1397,7 +1398,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpec
GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpecBool@%d ", nodeIndex);
+ dataLogF("SpecBool@%d ", nodeIndex);
#endif
SpeculatedType type = m_state.forNode(nodeIndex).m_type;
Node& node = m_jit.graph()[nodeIndex];
@@ -2046,6 +2047,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();
@@ -2064,6 +2128,18 @@ void SpeculativeJIT::compile(Node& node)
initConstantInfo(m_compileIndex);
break;
+ case Identity: {
+ // This could be done a lot better. We take the cheap way out because Identity
+ // is only going to stick around after CSE if we had prediction weirdness.
+ JSValueOperand operand(this, node.child1());
+ GPRTemporary resultTag(this);
+ GPRTemporary resultPayload(this);
+ m_jit.move(operand.tagGPR(), resultTag.gpr());
+ m_jit.move(operand.payloadGPR(), resultPayload.gpr());
+ jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
+ break;
+ }
+
case GetLocal: {
SpeculatedType prediction = node.variableAccessData()->prediction();
AbstractValue& value = block()->valuesAtHead.operand(node.local());
@@ -2366,7 +2442,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 +2470,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 +2495,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 +2646,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 +2660,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 +2713,68 @@ void SpeculativeJIT::compile(Node& node)
jsValueResult(resultTagReg, resultPayloadReg, m_compileIndex);
break;
}
+ case Array::Double: {
+ if (node.arrayMode().isInBounds()) {
+ if (node.arrayMode().isSaneChain()) {
+ JSGlobalObject* globalObject = m_jit.globalObjectFor(node.codeOrigin);
+ ASSERT(globalObject->arrayPrototypeChainIsSane());
+ globalObject->arrayPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
+ globalObject->objectPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
+ }
+
+ 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());
+ if (!node.arrayMode().isSaneChain())
+ 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 +2925,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 +2949,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 +3146,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 +3205,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 +3286,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 +3320,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 +3576,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 +3595,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 +3658,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 +3668,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 +3738,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 +3778,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 +3812,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 +3840,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 +3868,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;
@@ -3630,6 +3972,12 @@ void SpeculativeJIT::compile(Node& node)
break;
}
+ case InheritorIDWatchpoint: {
+ jsCast<JSFunction*>(node.function())->addInheritorIDWatchpoint(speculationWatchpoint());
+ noResult(m_compileIndex);
+ break;
+ }
+
case NewObject: {
GPRTemporary result(this);
GPRTemporary scratch(this);
@@ -3639,9 +3987,9 @@ void SpeculativeJIT::compile(Node& node)
MacroAssembler::JumpList slowPath;
- emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)->emptyObjectStructure()), resultGPR, scratchGPR, slowPath);
+ emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(node.structure()), resultGPR, scratchGPR, slowPath);
- addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR));
+ addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR, node.structure()));
cellResult(resultGPR, m_compileIndex);
break;
@@ -3810,7 +4158,7 @@ void SpeculativeJIT::compile(Node& node)
case CheckFunction: {
SpeculateCellOperand function(this, node.child1());
- speculationCheck(BadCache, JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function()));
+ speculationCheck(BadCache, JSValueSource::unboxedCell(function.gpr()), node.child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function()));
noResult(m_compileIndex);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 6c066c388..da6583c70 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -29,8 +29,10 @@
#if ENABLE(DFG_JIT)
#include "Arguments.h"
+#include "ArrayPrototype.h"
#include "DFGCallArrayAllocatorSlowPathGenerator.h"
#include "DFGSlowPathGenerator.h"
+#include "ObjectPrototype.h"
namespace JSC { namespace DFG {
@@ -1056,14 +1058,14 @@ void SpeculativeJIT::emitCall(Node& node)
jsValueResult(resultGPR, m_compileIndex, DataFormatJS, UseChildrenCalledExplicitly);
- m_jit.addJSCall(fastCall, slowCall, targetToCheck, callType, at(m_compileIndex).codeOrigin);
+ m_jit.addJSCall(fastCall, slowCall, targetToCheck, callType, calleeGPR, at(m_compileIndex).codeOrigin);
}
template<bool strict>
GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpecInt@%d ", nodeIndex);
+ dataLogF("SpecInt@%d ", nodeIndex);
#endif
SpeculatedType type = m_state.forNode(nodeIndex).m_type;
Node& node = at(nodeIndex);
@@ -1211,7 +1213,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex)
FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpecDouble@%d ", nodeIndex);
+ dataLogF("SpecDouble@%d ", nodeIndex);
#endif
SpeculatedType type = m_state.forNode(nodeIndex).m_type;
Node& node = at(nodeIndex);
@@ -1365,7 +1367,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpeculation)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpecCell@%d ", nodeIndex);
+ dataLogF("SpecCell@%d ", nodeIndex);
#endif
SpeculatedType type = m_state.forNode(nodeIndex).m_type;
Node& node = at(nodeIndex);
@@ -1441,7 +1443,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpec
GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("SpecBool@%d ", nodeIndex);
+ dataLogF("SpecBool@%d ", nodeIndex);
#endif
SpeculatedType type = m_state.forNode(nodeIndex).m_type;
Node& node = at(nodeIndex);
@@ -2128,6 +2130,16 @@ void SpeculativeJIT::compile(Node& node)
m_jit.addWeakReference(node.weakConstant());
initConstantInfo(m_compileIndex);
break;
+
+ case Identity: {
+ // This could be done a lot better. We take the cheap way out because Identity
+ // is only going to stick around after CSE if we had prediction weirdness.
+ JSValueOperand operand(this, node.child1());
+ GPRTemporary result(this, operand);
+ m_jit.move(operand.gpr(), result.gpr());
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
case GetLocal: {
SpeculatedType prediction = node.variableAccessData()->prediction();
@@ -2403,7 +2415,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 +2439,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 +2464,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 +2613,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 +2630,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 +2663,68 @@ void SpeculativeJIT::compile(Node& node)
jsValueResult(resultReg, m_compileIndex);
break;
}
+
+ case Array::Double: {
+ if (node.arrayMode().isInBounds()) {
+ if (node.arrayMode().isSaneChain()) {
+ JSGlobalObject* globalObject = m_jit.globalObjectFor(node.codeOrigin);
+ ASSERT(globalObject->arrayPrototypeChainIsSane());
+ globalObject->arrayPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
+ globalObject->objectPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
+ }
+
+ 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());
+ if (!node.arrayMode().isSaneChain())
+ 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 +2867,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 +2875,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 +2943,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 +3172,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 +3213,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 +3287,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 +3306,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 +3336,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 +3491,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 +3510,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 +3570,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 +3580,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 +3654,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 +3670,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 +3702,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 +3737,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 +3787,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 +3799,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 +3825,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;
@@ -3645,6 +3923,12 @@ void SpeculativeJIT::compile(Node& node)
cellResult(resultGPR, m_compileIndex);
break;
}
+
+ case InheritorIDWatchpoint: {
+ jsCast<JSFunction*>(node.function())->addInheritorIDWatchpoint(speculationWatchpoint());
+ noResult(m_compileIndex);
+ break;
+ }
case NewObject: {
GPRTemporary result(this);
@@ -3655,9 +3939,9 @@ void SpeculativeJIT::compile(Node& node)
MacroAssembler::JumpList slowPath;
- emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)->emptyObjectStructure()), resultGPR, scratchGPR, slowPath);
+ emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(node.structure()), resultGPR, scratchGPR, slowPath);
- addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR));
+ addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR, node.structure()));
cellResult(resultGPR, m_compileIndex);
break;
@@ -3813,7 +4097,7 @@ void SpeculativeJIT::compile(Node& node)
case CheckFunction: {
SpeculateCellOperand function(this, node.child1());
- speculationCheck(BadCache, JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function()));
+ speculationCheck(BadCache, JSValueRegs(function.gpr()), node.child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function()));
noResult(m_compileIndex);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
index 22b9395b5..9d6060d60 100644
--- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
@@ -167,7 +167,7 @@ public:
if (iter == m_map.end())
continue;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Zeroing the structure to hoist for %s because the ratio is %lf.\n",
+ dataLogF("Zeroing the structure to hoist for %s because the ratio is %lf.\n",
m_graph.nameOfVariableAccessData(variable), variable->voteRatio());
#endif
iter->value.m_structure = 0;
@@ -200,7 +200,7 @@ public:
JSValue value = m_graph.m_mustHandleValues[i];
if (!value || !value.isCell()) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Zeroing the structure to hoist for %s because the OSR entry value is not a cell: %s.\n",
+ dataLogF("Zeroing the structure to hoist for %s because the OSR entry value is not a cell: %s.\n",
m_graph.nameOfVariableAccessData(variable), value.description());
#endif
iter->value.m_structure = 0;
@@ -208,7 +208,7 @@ public:
}
if (value.asCell()->structure() != iter->value.m_structure) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Zeroing the structure to hoist for %s because the OSR entry value has structure %p and we wanted %p.\n",
+ dataLogF("Zeroing the structure to hoist for %s because the OSR entry value has structure %p and we wanted %p.\n",
m_graph.nameOfVariableAccessData(variable), value.asCell()->structure(), iter->value.m_structure);
#endif
iter->value.m_structure = 0;
@@ -223,10 +223,10 @@ public:
for (HashMap<VariableAccessData*, CheckData>::iterator it = m_map.begin();
it != m_map.end(); ++it) {
if (!it->value.m_structure) {
- dataLog("Not hoisting checks for %s because of heuristics.\n", m_graph.nameOfVariableAccessData(it->key));
+ dataLogF("Not hoisting checks for %s because of heuristics.\n", m_graph.nameOfVariableAccessData(it->key));
continue;
}
- dataLog("Hoisting checks for %s\n", m_graph.nameOfVariableAccessData(it->key));
+ dataLogF("Hoisting checks for %s\n", m_graph.nameOfVariableAccessData(it->key));
}
#endif // DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
diff --git a/Source/JavaScriptCore/dfg/DFGThunks.cpp b/Source/JavaScriptCore/dfg/DFGThunks.cpp
index 74d1967a8..ac0b45f60 100644
--- a/Source/JavaScriptCore/dfg/DFGThunks.cpp
+++ b/Source/JavaScriptCore/dfg/DFGThunks.cpp
@@ -213,6 +213,18 @@ MacroAssemblerCodeRef linkConstructThunkGenerator(JSGlobalData* globalData)
return linkForThunkGenerator(globalData, CodeForConstruct);
}
+// For closure optimizations, we only include calls, since if you're using closures for
+// object construction then you're going to lose big time anyway.
+MacroAssemblerCodeRef linkClosureCallThunkGenerator(JSGlobalData* globalData)
+{
+ CCallHelpers jit(globalData);
+
+ slowPathFor(jit, globalData, operationLinkClosureCall);
+
+ LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID);
+ return FINALIZE_CODE(patchBuffer, ("DFG link closure call slow path thunk"));
+}
+
static MacroAssemblerCodeRef virtualForThunkGenerator(
JSGlobalData* globalData, CodeSpecializationKind kind)
{
diff --git a/Source/JavaScriptCore/dfg/DFGThunks.h b/Source/JavaScriptCore/dfg/DFGThunks.h
index 11a06d107..c97e3bfb6 100644
--- a/Source/JavaScriptCore/dfg/DFGThunks.h
+++ b/Source/JavaScriptCore/dfg/DFGThunks.h
@@ -45,6 +45,8 @@ MacroAssemblerCodeRef throwExceptionFromCallSlowPathGenerator(JSGlobalData*);
MacroAssemblerCodeRef linkCallThunkGenerator(JSGlobalData*);
MacroAssemblerCodeRef linkConstructThunkGenerator(JSGlobalData*);
+MacroAssemblerCodeRef linkClosureCallThunkGenerator(JSGlobalData*);
+
MacroAssemblerCodeRef virtualCallThunkGenerator(JSGlobalData*);
MacroAssemblerCodeRef virtualConstructThunkGenerator(JSGlobalData*);
diff --git a/Source/JavaScriptCore/dfg/DFGValidate.cpp b/Source/JavaScriptCore/dfg/DFGValidate.cpp
index 2b26123d8..274b544b5 100644
--- a/Source/JavaScriptCore/dfg/DFGValidate.cpp
+++ b/Source/JavaScriptCore/dfg/DFGValidate.cpp
@@ -45,9 +45,9 @@ public:
#define VALIDATE(context, assertion) do { \
if (!(assertion)) { \
- dataLog("\n\n\nAt "); \
+ dataLogF("\n\n\nAt "); \
reportValidationContext context; \
- dataLog(": validation %s (%s:%d) failed.\n", #assertion, __FILE__, __LINE__); \
+ dataLogF(": validation %s (%s:%d) failed.\n", #assertion, __FILE__, __LINE__); \
dumpGraphIfAppropriate(); \
WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \
CRASH(); \
@@ -56,13 +56,13 @@ public:
#define V_EQUAL(context, left, right) do { \
if (left != right) { \
- dataLog("\n\n\nAt "); \
+ dataLogF("\n\n\nAt "); \
reportValidationContext context; \
- dataLog(": validation (%s = ", #left); \
+ dataLogF(": validation (%s = ", #left); \
dumpData(left); \
- dataLog(") == (%s = ", #right); \
+ dataLogF(") == (%s = ", #right); \
dumpData(right); \
- dataLog(") (%s:%d) failed.\n", __FILE__, __LINE__); \
+ dataLogF(") (%s:%d) failed.\n", __FILE__, __LINE__); \
dumpGraphIfAppropriate(); \
WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #left " == " #right); \
CRASH(); \
@@ -290,60 +290,60 @@ private:
void reportValidationContext(NodeIndex nodeIndex)
{
- dataLog("@%u", nodeIndex);
+ dataLogF("@%u", nodeIndex);
}
enum BlockTag { Block };
void reportValidationContext(BlockTag, BlockIndex blockIndex)
{
- dataLog("Block #%u", blockIndex);
+ dataLogF("Block #%u", blockIndex);
}
void reportValidationContext(NodeIndex nodeIndex, Edge edge)
{
- dataLog("@%u -> %s@%u", nodeIndex, useKindToString(edge.useKind()), edge.index());
+ dataLogF("@%u -> %s@%u", nodeIndex, useKindToString(edge.useKind()), edge.index());
}
void reportValidationContext(
VirtualRegister local, BlockIndex sourceBlockIndex, BlockTag, BlockIndex destinationBlockIndex)
{
- dataLog("r%d in Block #%u -> #%u", local, sourceBlockIndex, destinationBlockIndex);
+ dataLogF("r%d in Block #%u -> #%u", local, sourceBlockIndex, destinationBlockIndex);
}
void reportValidationContext(
VirtualRegister local, BlockIndex sourceBlockIndex, NodeIndex prevNodeIndex)
{
- dataLog("@%u for r%d in Block #%u", prevNodeIndex, local, sourceBlockIndex);
+ dataLogF("@%u for r%d in Block #%u", prevNodeIndex, local, sourceBlockIndex);
}
void reportValidationContext(
NodeIndex nodeIndex, BlockIndex blockIndex)
{
- dataLog("@%u in Block #%u", nodeIndex, blockIndex);
+ dataLogF("@%u in Block #%u", nodeIndex, blockIndex);
}
void reportValidationContext(
NodeIndex nodeIndex, NodeIndex nodeIndex2, BlockIndex blockIndex)
{
- dataLog("@%u and @%u in Block #%u", nodeIndex, nodeIndex2, blockIndex);
+ dataLogF("@%u and @%u in Block #%u", nodeIndex, nodeIndex2, blockIndex);
}
void reportValidationContext(
NodeIndex nodeIndex, BlockIndex blockIndex, NodeIndex expectedNodeIndex, Edge incomingEdge)
{
- dataLog("@%u in Block #%u, searching for @%u from @%u", nodeIndex, blockIndex, expectedNodeIndex, incomingEdge.index());
+ dataLogF("@%u in Block #%u, searching for @%u from @%u", nodeIndex, blockIndex, expectedNodeIndex, incomingEdge.index());
}
void dumpData(unsigned value)
{
- dataLog("%u", value);
+ dataLogF("%u", value);
}
void dumpGraphIfAppropriate()
{
if (m_graphDumpMode == DontDumpGraph)
return;
- dataLog("Graph at time of failure:\n");
+ dataLogF("Graph at time of failure:\n");
m_graph.dump();
}
};
diff --git a/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp b/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp
index fa36ccdb5..7fa109b62 100644
--- a/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp
+++ b/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp
@@ -36,9 +36,9 @@ namespace JSC { namespace DFG {
void VariableEventStream::logEvent(const VariableEvent& event)
{
- dataLog("seq#%u:", static_cast<unsigned>(size()));
+ dataLogF("seq#%u:", static_cast<unsigned>(size()));
event.dump(WTF::dataFile());
- dataLog(" ");
+ dataLogF(" ");
}
struct MinifiedGenerationInfo {
@@ -103,7 +103,7 @@ void VariableEventStream::reconstruct(
startIndex--;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Computing OSR exit recoveries starting at seq#%u.\n", startIndex);
+ dataLogF("Computing OSR exit recoveries starting at seq#%u.\n", startIndex);
#endif
// Step 2: Create a mock-up of the DFG's state and execute the events.
diff --git a/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp b/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp
index 86b33835d..eb3232e69 100644
--- a/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp
@@ -43,9 +43,9 @@ public:
bool run()
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Preserved vars: ");
+ dataLogF("Preserved vars: ");
m_graph.m_preservedVars.dump(WTF::dataFile());
- dataLog("\n");
+ dataLogF("\n");
#endif
ScoreBoard scoreBoard(m_graph, m_graph.m_preservedVars);
scoreBoard.assertClear();
@@ -62,8 +62,8 @@ public:
NodeIndex nodeIndex = block->at(indexInBlock);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
if (needsNewLine)
- dataLog("\n");
- dataLog(" @%u:", nodeIndex);
+ dataLogF("\n");
+ dataLogF(" @%u:", nodeIndex);
needsNewLine = true;
#endif
Node& node = m_graph[nodeIndex];
@@ -92,7 +92,7 @@ public:
VirtualRegister virtualRegister = scoreBoard.allocate();
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Assigning virtual register %u to node %u.",
+ dataLogF(" Assigning virtual register %u to node %u.",
virtualRegister, nodeIndex);
#endif
node.setVirtualRegister(virtualRegister);
@@ -105,7 +105,7 @@ public:
}
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
if (needsNewLine)
- dataLog("\n");
+ dataLogF("\n");
#endif
// 'm_numCalleeRegisters' is the number of locals and temporaries allocated
@@ -123,7 +123,7 @@ public:
if ((unsigned)codeBlock()->m_numCalleeRegisters < calleeRegisters)
codeBlock()->m_numCalleeRegisters = calleeRegisters;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Num callee registers: %u\n", calleeRegisters);
+ dataLogF("Num callee registers: %u\n", calleeRegisters);
#endif
return true;
diff --git a/Source/JavaScriptCore/disassembler/Disassembler.cpp b/Source/JavaScriptCore/disassembler/Disassembler.cpp
new file mode 100644
index 000000000..84bf2ec17
--- /dev/null
+++ b/Source/JavaScriptCore/disassembler/Disassembler.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 "Disassembler.h"
+
+#include "MacroAssemblerCodeRef.h"
+#include <wtf/DataLog.h>
+
+namespace JSC {
+
+void disassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, FILE* out)
+{
+ if (tryToDisassemble(codePtr, size, prefix, out))
+ return;
+
+ fprintf(out, "%sdisassembly not available for range %p...%p\n", prefix, codePtr.executableAddress(), static_cast<char*>(codePtr.executableAddress()) + size);
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/disassembler/Disassembler.h b/Source/JavaScriptCore/disassembler/Disassembler.h
index 7d7400ac8..b87f3d33a 100644
--- a/Source/JavaScriptCore/disassembler/Disassembler.h
+++ b/Source/JavaScriptCore/disassembler/Disassembler.h
@@ -43,6 +43,10 @@ inline bool tryToDisassemble(const MacroAssemblerCodePtr&, size_t, const char*,
}
#endif
+// Prints either the disassembly, or a line of text indicating that disassembly failed and
+// the range of machine code addresses.
+void disassemble(const MacroAssemblerCodePtr&, size_t, const char* prefix, FILE* out);
+
} // namespace JSC
#endif // Disassembler_h
diff --git a/Source/JavaScriptCore/heap/BlockAllocator.cpp b/Source/JavaScriptCore/heap/BlockAllocator.cpp
index daba93805..2d7b57f9a 100644
--- a/Source/JavaScriptCore/heap/BlockAllocator.cpp
+++ b/Source/JavaScriptCore/heap/BlockAllocator.cpp
@@ -36,7 +36,7 @@ namespace JSC {
BlockAllocator::BlockAllocator()
: m_copiedRegionSet(CopiedBlock::blockSize)
, m_markedRegionSet(MarkedBlock::blockSize)
- , m_weakRegionSet(WeakBlock::blockSize)
+ , m_weakAndMarkStackRegionSet(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 f8ce39530..75c59b783 100644
--- a/Source/JavaScriptCore/heap/BlockAllocator.h
+++ b/Source/JavaScriptCore/heap/BlockAllocator.h
@@ -37,6 +37,7 @@ namespace JSC {
class BlockAllocator;
class CopiedBlock;
+class MarkStackSegment;
class MarkedBlock;
class Region;
class WeakBlock;
@@ -185,7 +186,8 @@ private:
RegionSet m_copiedRegionSet;
RegionSet m_markedRegionSet;
- RegionSet m_weakRegionSet;
+ // WeakBlocks and MarkStackSegments use the same RegionSet since they're the same size.
+ RegionSet m_weakAndMarkStackRegionSet;
DoublyLinkedList<Region> m_emptyRegions;
size_t m_numberOfEmptyRegions;
@@ -315,7 +317,13 @@ inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<MarkedBlock>()
template <>
inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<WeakBlock>()
{
- return m_weakRegionSet;
+ return m_weakAndMarkStackRegionSet;
+}
+
+template <>
+inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<MarkStackSegment>()
+{
+ return m_weakAndMarkStackRegionSet;
}
template <>
@@ -333,7 +341,13 @@ inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<MarkedB
template <>
inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<WeakBlock> >()
{
- return m_weakRegionSet;
+ return m_weakAndMarkStackRegionSet;
+}
+
+template <>
+inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<MarkStackSegment> >()
+{
+ return m_weakAndMarkStackRegionSet;
}
template <typename T>
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..f513fafab 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 {
@@ -56,7 +56,7 @@ GCThreadSharedData::GCThreadSharedData(JSGlobalData* globalData)
: m_globalData(globalData)
, m_copiedSpace(&globalData->heap.m_storageSpace)
, m_shouldHashConst(false)
- , m_sharedMarkStack(m_segmentAllocator)
+ , m_sharedMarkStack(globalData->heap.blockAllocator())
, m_numberOfActiveParallelMarkers(0)
, m_parallelMarkersShouldExit(false)
, m_blocksToCopy(globalData->heap.m_blockSnapshot)
@@ -110,7 +110,6 @@ void GCThreadSharedData::reset()
ASSERT(m_sharedMarkStack.isEmpty());
#if ENABLE(PARALLEL_GC)
- m_segmentAllocator.shrinkReserve();
m_opaqueRoots.clear();
#else
ASSERT(m_opaqueRoots.isEmpty());
diff --git a/Source/JavaScriptCore/heap/GCThreadSharedData.h b/Source/JavaScriptCore/heap/GCThreadSharedData.h
index f341afc04..b80cc5af2 100644
--- a/Source/JavaScriptCore/heap/GCThreadSharedData.h
+++ b/Source/JavaScriptCore/heap/GCThreadSharedData.h
@@ -80,8 +80,6 @@ private:
JSGlobalData* m_globalData;
CopiedSpace* m_copiedSpace;
- MarkStackSegmentAllocator m_segmentAllocator;
-
bool m_shouldHashConst;
Vector<GCThread*> m_gcThreads;
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..9ff318b08 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"
@@ -76,7 +76,7 @@ struct GCTimer {
}
~GCTimer()
{
- dataLog("%s: %.2lfms (avg. %.2lf, min. %.2lf, max. %.2lf)\n", m_name, m_time * 1000, m_time * 1000 / m_count, m_min*1000, m_max*1000);
+ dataLogF("%s: %.2lfms (avg. %.2lf, min. %.2lf, max. %.2lf)\n", m_name, m_time * 1000, m_time * 1000 / m_count, m_min*1000, m_max*1000);
}
double m_time;
double m_min;
@@ -126,7 +126,7 @@ struct GCCounter {
}
~GCCounter()
{
- dataLog("%s: %zu values (avg. %zu, min. %zu, max. %zu)\n", m_name, m_total, m_total / m_count, m_min, m_max);
+ dataLogF("%s: %zu values (avg. %zu, min. %zu, max. %zu)\n", m_name, m_total, m_total / m_count, m_min, m_max);
}
const char* m_name;
size_t m_count;
diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h
index d0d03959b..90c9f2ab1 100644
--- a/Source/JavaScriptCore/heap/Heap.h
+++ b/Source/JavaScriptCore/heap/Heap.h
@@ -174,6 +174,8 @@ namespace JSC {
bool isPagedOut(double deadline);
void didStartVMShutdown();
+
+ const JITStubRoutineSet& jitStubRoutines() { return m_jitStubRoutines; }
private:
friend class CodeBlock;
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..2b98fe711 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)
@@ -75,28 +75,28 @@ void HeapStatistics::logStatistics()
#error "The HeapStatistics module is not supported on this platform."
#endif
if (!vmName || !suiteName || !benchmarkName)
- dataLog("HeapStatistics: {\"max_rss\": %ld", usage.ru_maxrss);
+ dataLogF("HeapStatistics: {\"max_rss\": %ld", usage.ru_maxrss);
else
- dataLog("HeapStatistics: {\"max_rss\": %ld, \"vm_name\": \"%s\", \"suite_name\": \"%s\", \"benchmark_name\": \"%s\"",
+ dataLogF("HeapStatistics: {\"max_rss\": %ld, \"vm_name\": \"%s\", \"suite_name\": \"%s\", \"benchmark_name\": \"%s\"",
usage.ru_maxrss, vmName, suiteName, benchmarkName);
if (Options::recordGCPauseTimes()) {
- dataLog(", \"pause_times\": [");
- Deque<double>::iterator startIt = s_pauseTimeStarts->begin();
- Deque<double>::iterator endIt = s_pauseTimeEnds->begin();
+ dataLogF(", \"pause_times\": [");
+ 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);
+ dataLogF("[%f, %f]", *startIt, *endIt);
++startIt;
++endIt;
}
while (startIt != s_pauseTimeStarts->end() && endIt != s_pauseTimeEnds->end()) {
- dataLog(", [%f, %f]", *startIt, *endIt);
+ dataLogF(", [%f, %f]", *startIt, *endIt);
++startIt;
++endIt;
}
- dataLog("], \"start_time\": %f, \"end_time\": %f", s_startTime, s_endTime);
+ dataLogF("], \"start_time\": %f, \"end_time\": %f", s_startTime, s_endTime);
}
- dataLog("}\n");
+ dataLogF("}\n");
}
void HeapStatistics::exitWithFailure()
@@ -228,20 +228,20 @@ inline size_t StorageStatistics::storageCapacity()
void HeapStatistics::showObjectStatistics(Heap* heap)
{
- dataLog("\n=== Heap Statistics: ===\n");
- dataLog("size: %ldkB\n", static_cast<long>(heap->m_sizeAfterLastCollect / KB));
- dataLog("capacity: %ldkB\n", static_cast<long>(heap->capacity() / KB));
- dataLog("pause time: %lfms\n\n", heap->m_lastGCLength);
+ dataLogF("\n=== Heap Statistics: ===\n");
+ dataLogF("size: %ldkB\n", static_cast<long>(heap->m_sizeAfterLastCollect / KB));
+ dataLogF("capacity: %ldkB\n", static_cast<long>(heap->capacity() / KB));
+ dataLogF("pause time: %lfms\n\n", heap->m_lastGCLength);
StorageStatistics storageStatistics;
heap->m_objectSpace.forEachLiveCell(storageStatistics);
- dataLog("wasted .property storage: %ldkB (%ld%%)\n",
+ dataLogF("wasted .property storage: %ldkB (%ld%%)\n",
static_cast<long>(
(storageStatistics.storageCapacity() - storageStatistics.storageSize()) / KB),
static_cast<long>(
(storageStatistics.storageCapacity() - storageStatistics.storageSize()) * 100
/ storageStatistics.storageCapacity()));
- dataLog("objects with out-of-line .property storage: %ld (%ld%%)\n",
+ dataLogF("objects with out-of-line .property storage: %ld (%ld%%)\n",
static_cast<long>(
storageStatistics.objectWithOutOfLineStorageCount()),
static_cast<long>(
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/JITStubRoutineSet.h b/Source/JavaScriptCore/heap/JITStubRoutineSet.h
index cb76ac8bd..2c2e9fa86 100644
--- a/Source/JavaScriptCore/heap/JITStubRoutineSet.h
+++ b/Source/JavaScriptCore/heap/JITStubRoutineSet.h
@@ -65,6 +65,9 @@ public:
void traceMarkedStubRoutines(SlotVisitor&);
+ unsigned size() const { return m_listOfRoutines.size(); }
+ GCAwareJITStubRoutine* at(unsigned i) const { return m_listOfRoutines[i]; }
+
private:
void markSlow(uintptr_t address);
diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp
index 582439fd2..755a0ad50 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>
@@ -45,84 +45,35 @@
namespace JSC {
-MarkStackSegmentAllocator::MarkStackSegmentAllocator()
- : m_nextFreeSegment(0)
-{
- m_lock.Init();
-}
-
-MarkStackSegmentAllocator::~MarkStackSegmentAllocator()
-{
- shrinkReserve();
-}
-
-MarkStackSegment* MarkStackSegmentAllocator::allocate()
-{
- {
- SpinLockHolder locker(&m_lock);
- if (m_nextFreeSegment) {
- MarkStackSegment* result = m_nextFreeSegment;
- m_nextFreeSegment = result->m_previous;
- return result;
- }
- }
-
- return static_cast<MarkStackSegment*>(OSAllocator::reserveAndCommit(Options::gcMarkStackSegmentSize()));
-}
-
-void MarkStackSegmentAllocator::release(MarkStackSegment* segment)
-{
- SpinLockHolder locker(&m_lock);
- segment->m_previous = m_nextFreeSegment;
- m_nextFreeSegment = segment;
-}
-
-void MarkStackSegmentAllocator::shrinkReserve()
-{
- MarkStackSegment* segments;
- {
- SpinLockHolder locker(&m_lock);
- segments = m_nextFreeSegment;
- m_nextFreeSegment = 0;
- }
- while (segments) {
- MarkStackSegment* toFree = segments;
- segments = segments->m_previous;
- OSAllocator::decommitAndRelease(toFree, Options::gcMarkStackSegmentSize());
- }
-}
-
-MarkStackArray::MarkStackArray(MarkStackSegmentAllocator& allocator)
- : m_allocator(allocator)
+MarkStackArray::MarkStackArray(BlockAllocator& blockAllocator)
+ : m_blockAllocator(blockAllocator)
, m_segmentCapacity(MarkStackSegment::capacityFromSize(Options::gcMarkStackSegmentSize()))
, m_top(0)
- , m_numberOfPreviousSegments(0)
+ , m_numberOfSegments(0)
{
- m_topSegment = m_allocator.allocate();
-#if !ASSERT_DISABLED
- m_topSegment->m_top = 0;
-#endif
- m_topSegment->m_previous = 0;
+ ASSERT(MarkStackSegment::blockSize == WeakBlock::blockSize);
+ m_segments.push(MarkStackSegment::create(m_blockAllocator.allocate<MarkStackSegment>()));
+ m_numberOfSegments++;
}
MarkStackArray::~MarkStackArray()
{
- ASSERT(!m_topSegment->m_previous);
- m_allocator.release(m_topSegment);
+ ASSERT(m_numberOfSegments == 1 && m_segments.size() == 1);
+ m_blockAllocator.deallocate(MarkStackSegment::destroy(m_segments.removeHead()));
}
void MarkStackArray::expand()
{
- ASSERT(m_topSegment->m_top == m_segmentCapacity);
+ ASSERT(m_segments.head()->m_top == m_segmentCapacity);
- m_numberOfPreviousSegments++;
+ MarkStackSegment* nextSegment = MarkStackSegment::create(m_blockAllocator.allocate<MarkStackSegment>());
+ m_numberOfSegments++;
- MarkStackSegment* nextSegment = m_allocator.allocate();
#if !ASSERT_DISABLED
nextSegment->m_top = 0;
#endif
- nextSegment->m_previous = m_topSegment;
- m_topSegment = nextSegment;
+
+ m_segments.push(nextSegment);
setTopForEmptySegment();
validatePrevious();
}
@@ -132,14 +83,9 @@ bool MarkStackArray::refill()
validatePrevious();
if (top())
return true;
- MarkStackSegment* toFree = m_topSegment;
- MarkStackSegment* previous = m_topSegment->m_previous;
- if (!previous)
- return false;
- ASSERT(m_numberOfPreviousSegments);
- m_numberOfPreviousSegments--;
- m_topSegment = previous;
- m_allocator.release(toFree);
+ m_blockAllocator.deallocate(MarkStackSegment::destroy(m_segments.removeHead()));
+ ASSERT(m_numberOfSegments > 1);
+ m_numberOfSegments--;
setTopForFullSegment();
validatePrevious();
return true;
@@ -153,7 +99,7 @@ void MarkStackArray::donateSomeCellsTo(MarkStackArray& other)
ASSERT(m_segmentCapacity == other.m_segmentCapacity);
- size_t segmentsToDonate = (m_numberOfPreviousSegments + 2 - 1) / 2; // Round up to donate 1 / 1 previous segments.
+ size_t segmentsToDonate = m_numberOfSegments / 2; // If we only have one segment (our head) we don't donate any segments.
if (!segmentsToDonate) {
size_t cellsToDonate = m_top / 2; // Round down to donate 0 / 1 cells.
@@ -167,21 +113,23 @@ void MarkStackArray::donateSomeCellsTo(MarkStackArray& other)
validatePrevious();
other.validatePrevious();
- MarkStackSegment* previous = m_topSegment->m_previous;
+ // Remove our head and the head of the other list before we start moving segments around.
+ // We'll add them back on once we're done donating.
+ MarkStackSegment* myHead = m_segments.removeHead();
+ MarkStackSegment* otherHead = other.m_segments.removeHead();
+
while (segmentsToDonate--) {
- ASSERT(previous);
- ASSERT(m_numberOfPreviousSegments);
-
- MarkStackSegment* current = previous;
- previous = current->m_previous;
-
- current->m_previous = other.m_topSegment->m_previous;
- other.m_topSegment->m_previous = current;
-
- m_numberOfPreviousSegments--;
- other.m_numberOfPreviousSegments++;
+ MarkStackSegment* current = m_segments.removeHead();
+ ASSERT(current);
+ ASSERT(m_numberOfSegments > 1);
+ other.m_segments.push(current);
+ m_numberOfSegments--;
+ other.m_numberOfSegments++;
}
- m_topSegment->m_previous = previous;
+
+ // Put the original heads back in their places.
+ m_segments.push(myHead);
+ other.m_segments.push(otherHead);
validatePrevious();
other.validatePrevious();
@@ -198,21 +146,21 @@ void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other, size_t idleThread
other.validatePrevious();
// If other has an entire segment, steal it and return.
- if (other.m_topSegment->m_previous) {
- ASSERT(other.m_topSegment->m_previous->m_top == m_segmentCapacity);
-
- // First remove a segment from other.
- MarkStackSegment* current = other.m_topSegment->m_previous;
- other.m_topSegment->m_previous = current->m_previous;
- other.m_numberOfPreviousSegments--;
-
- ASSERT(!!other.m_numberOfPreviousSegments == !!other.m_topSegment->m_previous);
-
- // Now add it to this.
- current->m_previous = m_topSegment->m_previous;
- m_topSegment->m_previous = current;
- m_numberOfPreviousSegments++;
-
+ if (other.m_numberOfSegments > 1) {
+ // Move the heads of the lists aside. We'll push them back on after.
+ MarkStackSegment* otherHead = other.m_segments.removeHead();
+ MarkStackSegment* myHead = m_segments.removeHead();
+
+ ASSERT(other.m_segments.head()->m_top == m_segmentCapacity);
+
+ m_segments.push(other.m_segments.removeHead());
+
+ m_numberOfSegments++;
+ other.m_numberOfSegments--;
+
+ m_segments.push(myHead);
+ other.m_segments.push(otherHead);
+
validatePrevious();
other.validatePrevious();
return;
diff --git a/Source/JavaScriptCore/heap/MarkStack.h b/Source/JavaScriptCore/heap/MarkStack.h
index 0245e4be5..2a7f04450 100644
--- a/Source/JavaScriptCore/heap/MarkStack.h
+++ b/Source/JavaScriptCore/heap/MarkStack.h
@@ -27,19 +27,19 @@
#define MarkStack_h
#if ENABLE(OBJECT_MARK_LOGGING)
-#define MARK_LOG_MESSAGE0(message) dataLog(message)
-#define MARK_LOG_MESSAGE1(message, arg1) dataLog(message, arg1)
-#define MARK_LOG_MESSAGE2(message, arg1, arg2) dataLog(message, arg1, arg2)
+#define MARK_LOG_MESSAGE0(message) dataLogF(message)
+#define MARK_LOG_MESSAGE1(message, arg1) dataLogF(message, arg1)
+#define MARK_LOG_MESSAGE2(message, arg1, arg2) dataLogF(message, arg1, arg2)
#define MARK_LOG_ROOT(visitor, rootName) \
- dataLog("\n%s: ", rootName); \
+ dataLogF("\n%s: ", rootName); \
(visitor).resetChildCount()
#define MARK_LOG_PARENT(visitor, parent) \
- dataLog("\n%p (%s): ", parent, parent->className() ? parent->className() : "unknown"); \
+ dataLogF("\n%p (%s): ", parent, parent->className() ? parent->className() : "unknown"); \
(visitor).resetChildCount()
#define MARK_LOG_CHILD(visitor, child) \
if ((visitor).childCount()) \
- dataLogString(", "); \
- dataLog("%p", child); \
+ dataLogFString(", "); \
+ dataLogF("%p", child); \
(visitor).incrementChildCount()
#else
#define MARK_LOG_MESSAGE0(message) do { } while (false)
@@ -50,19 +50,27 @@
#define MARK_LOG_CHILD(visitor, child) do { } while (false)
#endif
+#include "HeapBlock.h"
#include <wtf/StdLibExtras.h>
-#include <wtf/TCSpinLock.h>
namespace JSC {
+class BlockAllocator;
+class DeadBlock;
class JSCell;
-struct MarkStackSegment {
- MarkStackSegment* m_previous;
+class MarkStackSegment : public HeapBlock<MarkStackSegment> {
+public:
+ MarkStackSegment(Region* region)
+ : HeapBlock<MarkStackSegment>(region)
#if !ASSERT_DISABLED
- size_t m_top;
+ , m_top(0)
#endif
-
+ {
+ }
+
+ static MarkStackSegment* create(DeadBlock*);
+
const JSCell** data()
{
return bitwise_cast<const JSCell**>(this + 1);
@@ -77,26 +85,17 @@ struct MarkStackSegment {
{
return sizeof(MarkStackSegment) + capacity * sizeof(const JSCell*);
}
-};
-class MarkStackSegmentAllocator {
-public:
- MarkStackSegmentAllocator();
- ~MarkStackSegmentAllocator();
-
- MarkStackSegment* allocate();
- void release(MarkStackSegment*);
-
- void shrinkReserve();
-
-private:
- SpinLock m_lock;
- MarkStackSegment* m_nextFreeSegment;
+ static const size_t blockSize = 4 * KB;
+
+#if !ASSERT_DISABLED
+ size_t m_top;
+#endif
};
class MarkStackArray {
public:
- MarkStackArray(MarkStackSegmentAllocator&);
+ MarkStackArray(BlockAllocator&);
~MarkStackArray();
void append(const JSCell*);
@@ -122,12 +121,12 @@ private:
void validatePrevious();
- MarkStackSegment* m_topSegment;
- MarkStackSegmentAllocator& m_allocator;
+ DoublyLinkedList<MarkStackSegment> m_segments;
+ BlockAllocator& m_blockAllocator;
size_t m_segmentCapacity;
size_t m_top;
- size_t m_numberOfPreviousSegments;
+ size_t m_numberOfSegments;
};
diff --git a/Source/JavaScriptCore/heap/MarkStackInlineMethods.h b/Source/JavaScriptCore/heap/MarkStackInlines.h
index d3276d7fa..1595e843e 100644
--- a/Source/JavaScriptCore/heap/MarkStackInlineMethods.h
+++ b/Source/JavaScriptCore/heap/MarkStackInlines.h
@@ -23,43 +23,48 @@
* 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"
namespace JSC {
+inline MarkStackSegment* MarkStackSegment::create(DeadBlock* block)
+{
+ return new (NotNull, block) MarkStackSegment(block->region());
+}
+
inline size_t MarkStackArray::postIncTop()
{
size_t result = m_top++;
- ASSERT(result == m_topSegment->m_top++);
+ ASSERT(result == m_segments.head()->m_top++);
return result;
}
-
+
inline size_t MarkStackArray::preDecTop()
{
size_t result = --m_top;
- ASSERT(result == --m_topSegment->m_top);
+ ASSERT(result == --m_segments.head()->m_top);
return result;
}
-
+
inline void MarkStackArray::setTopForFullSegment()
{
- ASSERT(m_topSegment->m_top == m_segmentCapacity);
+ ASSERT(m_segments.head()->m_top == m_segmentCapacity);
m_top = m_segmentCapacity;
}
inline void MarkStackArray::setTopForEmptySegment()
{
- ASSERT(!m_topSegment->m_top);
+ ASSERT(!m_segments.head()->m_top);
m_top = 0;
}
inline size_t MarkStackArray::top()
{
- ASSERT(m_top == m_topSegment->m_top);
+ ASSERT(m_top == m_segments.head()->m_top);
return m_top;
}
@@ -69,9 +74,9 @@ inline void MarkStackArray::validatePrevious() { }
inline void MarkStackArray::validatePrevious()
{
unsigned count = 0;
- for (MarkStackSegment* current = m_topSegment->m_previous; current; current = current->m_previous)
+ for (MarkStackSegment* current = m_segments.head(); current; current = current->next())
count++;
- ASSERT(count == m_numberOfPreviousSegments);
+ ASSERT(m_segments.size() == m_numberOfSegments);
}
#endif
@@ -79,7 +84,7 @@ inline void MarkStackArray::append(const JSCell* cell)
{
if (m_top == m_segmentCapacity)
expand();
- m_topSegment->data()[postIncTop()] = cell;
+ m_segments.head()->data()[postIncTop()] = cell;
}
inline bool MarkStackArray::canRemoveLast()
@@ -89,15 +94,15 @@ inline bool MarkStackArray::canRemoveLast()
inline const JSCell* MarkStackArray::removeLast()
{
- return m_topSegment->data()[preDecTop()];
+ return m_segments.head()->data()[preDecTop()];
}
inline bool MarkStackArray::isEmpty()
{
if (m_top)
return false;
- if (m_topSegment->m_previous) {
- ASSERT(m_topSegment->m_previous->m_top == m_segmentCapacity);
+ if (m_segments.head()->next()) {
+ ASSERT(m_segments.head()->next()->m_top == m_segmentCapacity);
return false;
}
return true;
@@ -105,9 +110,10 @@ inline bool MarkStackArray::isEmpty()
inline size_t MarkStackArray::size()
{
- return m_top + m_segmentCapacity * m_numberOfPreviousSegments;
+ return m_top + m_segmentCapacity * (m_numberOfSegments - 1);
}
} // namespace JSC
-#endif
+#endif // MarkStackInlines_h
+
diff --git a/Source/JavaScriptCore/heap/MarkedBlock.h b/Source/JavaScriptCore/heap/MarkedBlock.h
index f2f2a720d..9080aaef4 100644
--- a/Source/JavaScriptCore/heap/MarkedBlock.h
+++ b/Source/JavaScriptCore/heap/MarkedBlock.h
@@ -40,7 +40,7 @@
#if HEAP_LOG_BLOCK_STATE_TRANSITIONS
#define HEAP_LOG_BLOCK_STATE_TRANSITION(block) do { \
- dataLog( \
+ dataLogF( \
"%s:%d %s: block %s = %p, %d\n", \
__FILE__, __LINE__, __FUNCTION__, \
#block, (block), (block)->m_state); \
diff --git a/Source/JavaScriptCore/heap/SlotVisitor.cpp b/Source/JavaScriptCore/heap/SlotVisitor.cpp
index 3919705d0..3ff4b48fa 100644
--- a/Source/JavaScriptCore/heap/SlotVisitor.cpp
+++ b/Source/JavaScriptCore/heap/SlotVisitor.cpp
@@ -1,9 +1,10 @@
#include "config.h"
#include "SlotVisitor.h"
+#include "SlotVisitorInlines.h"
#include "ConservativeRoots.h"
#include "CopiedSpace.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "GCThread.h"
#include "JSArray.h"
#include "JSDestructibleObject.h"
@@ -15,7 +16,7 @@
namespace JSC {
SlotVisitor::SlotVisitor(GCThreadSharedData& shared)
- : m_stack(shared.m_segmentAllocator)
+ : m_stack(shared.m_globalData->heap.blockAllocator())
, m_visitCount(0)
, m_isInParallelMode(false)
, m_shared(shared)
@@ -335,12 +336,12 @@ void SlotVisitor::finalizeUnconditionalFinalizers()
void SlotVisitor::validate(JSCell* cell)
{
if (!cell) {
- dataLog("cell is NULL\n");
+ dataLogF("cell is NULL\n");
CRASH();
}
if (!cell->structure()) {
- dataLog("cell at %p has a null structure\n" , cell);
+ dataLogF("cell at %p has a null structure\n" , cell);
CRASH();
}
@@ -353,7 +354,7 @@ void SlotVisitor::validate(JSCell* cell)
parentClassName = cell->structure()->structure()->JSCell::classInfo()->className;
if (cell->structure()->JSCell::classInfo())
ourClassName = cell->structure()->JSCell::classInfo()->className;
- dataLog("parent structure (%p <%s>) of cell at %p doesn't match cell's structure (%p <%s>)\n",
+ dataLogF("parent structure (%p <%s>) of cell at %p doesn't match cell's structure (%p <%s>)\n",
cell->structure()->structure(), parentClassName, cell, cell->structure(), ourClassName);
CRASH();
}
diff --git a/Source/JavaScriptCore/heap/SlotVisitor.h b/Source/JavaScriptCore/heap/SlotVisitor.h
index dcd4b75ef..53c7de64f 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>
@@ -36,6 +36,7 @@ namespace JSC {
class ConservativeRoots;
class GCThreadSharedData;
class Heap;
+template<typename T> class Weak;
template<typename T> class WriteBarrierBase;
template<typename T> class JITWriteBarrier;
@@ -56,6 +57,8 @@ public:
template<typename T>
void appendUnbarrieredPointer(T**);
void appendUnbarrieredValue(JSValue*);
+ template<typename T>
+ void appendUnbarrieredWeak(Weak<T>*);
void addOpaqueRoot(void*);
bool containsOpaqueRoot(void*);
diff --git a/Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h b/Source/JavaScriptCore/heap/SlotVisitorInlines.h
index e5908bf36..ea8126f87 100644
--- a/Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h
+++ b/Source/JavaScriptCore/heap/SlotVisitorInlines.h
@@ -23,12 +23,13 @@
* 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"
+#include "Weak.h"
namespace JSC {
@@ -66,6 +67,14 @@ ALWAYS_INLINE void SlotVisitor::append(JSCell** slot)
internalAppend(*slot);
}
+template<typename T>
+ALWAYS_INLINE void SlotVisitor::appendUnbarrieredWeak(Weak<T>* weak)
+{
+ ASSERT(weak);
+ if (weak->get())
+ internalAppend(weak->get());
+}
+
ALWAYS_INLINE void SlotVisitor::internalAppend(JSValue value)
{
if (!value || !value.isCell())
@@ -170,5 +179,5 @@ inline void SlotVisitor::copyLater(void* ptr, size_t bytes)
} // namespace JSC
-#endif // SlotVisitorInlineMethods_h
+#endif // SlotVisitorInlines_h
diff --git a/Source/JavaScriptCore/heap/Weak.h b/Source/JavaScriptCore/heap/Weak.h
index 3c3d1d0ce..efb2a9a56 100644
--- a/Source/JavaScriptCore/heap/Weak.h
+++ b/Source/JavaScriptCore/heap/Weak.h
@@ -151,6 +151,11 @@ template<typename T> inline WeakImpl* Weak<T>::hashTableDeletedValue()
return reinterpret_cast<WeakImpl*>(-1);
}
+template <typename T> inline bool operator==(const Weak<T>& lhs, const Weak<T>& rhs)
+{
+ return lhs.get() == rhs.get();
+}
+
// This function helps avoid modifying a weak table while holding an iterator into it. (Object allocation
// can run a finalizer that modifies the table. We avoid that by requiring a pre-constructed object as our value.)
template<typename Map, typename Key, typename Value> inline void weakAdd(Map& map, const Key& key, Value value)
diff --git a/Source/JavaScriptCore/interpreter/CallFrame.cpp b/Source/JavaScriptCore/interpreter/CallFrame.cpp
index 6dcf354b3..ac286c36c 100644
--- a/Source/JavaScriptCore/interpreter/CallFrame.cpp
+++ b/Source/JavaScriptCore/interpreter/CallFrame.cpp
@@ -40,7 +40,7 @@ void CallFrame::dumpCaller()
JSValue function;
interpreter()->retrieveLastCaller(this, signedLineNumber, sourceID, urlString, function);
- dataLog("Callpoint => %s:%d\n", urlString.utf8().data(), signedLineNumber);
+ dataLogF("Callpoint => %s:%d\n", urlString.utf8().data(), signedLineNumber);
}
JSStack* CallFrame::stack()
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
index 397ac8474..ad89505fc 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -380,16 +380,16 @@ void Interpreter::dumpCallFrame(CallFrame*)
void Interpreter::dumpCallFrame(CallFrame* callFrame)
{
- callFrame->codeBlock()->dump(callFrame);
+ callFrame->codeBlock()->dump();
dumpRegisters(callFrame);
}
void Interpreter::dumpRegisters(CallFrame* callFrame)
{
- dataLog("Register frame: \n\n");
- dataLog("-----------------------------------------------------------------------------\n");
- dataLog(" use | address | value \n");
- dataLog("-----------------------------------------------------------------------------\n");
+ dataLogF("Register frame: \n\n");
+ dataLogF("-----------------------------------------------------------------------------\n");
+ dataLogF(" use | address | value \n");
+ dataLogF("-----------------------------------------------------------------------------\n");
CodeBlock* codeBlock = callFrame->codeBlock();
const Register* it;
@@ -401,32 +401,32 @@ void Interpreter::dumpRegisters(CallFrame* callFrame)
JSValue v = it->jsValue();
int registerNumber = it - callFrame->registers();
String name = codeBlock->nameForRegister(registerNumber);
- dataLog("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, v.description(), (long long)JSValue::encode(v));
+ dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, v.description(), (long long)JSValue::encode(v));
it++;
}
- dataLog("-----------------------------------------------------------------------------\n");
- dataLog("[ArgumentCount] | %10p | %lu \n", it, (unsigned long) callFrame->argumentCount());
+ dataLogF("-----------------------------------------------------------------------------\n");
+ dataLogF("[ArgumentCount] | %10p | %lu \n", it, (unsigned long) callFrame->argumentCount());
++it;
- dataLog("[CallerFrame] | %10p | %p \n", it, callFrame->callerFrame());
+ dataLogF("[CallerFrame] | %10p | %p \n", it, callFrame->callerFrame());
++it;
- dataLog("[Callee] | %10p | %p \n", it, callFrame->callee());
+ dataLogF("[Callee] | %10p | %p \n", it, callFrame->callee());
++it;
- dataLog("[ScopeChain] | %10p | %p \n", it, callFrame->scope());
+ dataLogF("[ScopeChain] | %10p | %p \n", it, callFrame->scope());
++it;
#if ENABLE(JIT)
AbstractPC pc = callFrame->abstractReturnPC(callFrame->globalData());
if (pc.hasJITReturnAddress())
- dataLog("[ReturnJITPC] | %10p | %p \n", it, pc.jitReturnAddress().value());
+ dataLogF("[ReturnJITPC] | %10p | %p \n", it, pc.jitReturnAddress().value());
#endif
unsigned bytecodeOffset = 0;
int line = 0;
getCallerInfo(&callFrame->globalData(), callFrame, line, bytecodeOffset);
- dataLog("[ReturnVPC] | %10p | %d (line %d)\n", it, bytecodeOffset, line);
+ dataLogF("[ReturnVPC] | %10p | %d (line %d)\n", it, bytecodeOffset, line);
++it;
- dataLog("[CodeBlock] | %10p | %p \n", it, callFrame->codeBlock());
+ dataLogF("[CodeBlock] | %10p | %p \n", it, callFrame->codeBlock());
++it;
- dataLog("-----------------------------------------------------------------------------\n");
+ dataLogF("-----------------------------------------------------------------------------\n");
int registerCount = 0;
@@ -436,23 +436,23 @@ void Interpreter::dumpRegisters(CallFrame* callFrame)
JSValue v = it->jsValue();
int registerNumber = it - callFrame->registers();
String name = codeBlock->nameForRegister(registerNumber);
- dataLog("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, v.description(), (long long)JSValue::encode(v));
+ dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, v.description(), (long long)JSValue::encode(v));
++it;
++registerCount;
} while (it != end);
}
- dataLog("-----------------------------------------------------------------------------\n");
+ dataLogF("-----------------------------------------------------------------------------\n");
end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars;
if (it != end) {
do {
JSValue v = (*it).jsValue();
- dataLog("[r% 3d] | %10p | %-16s 0x%lld \n", registerCount, it, v.description(), (long long)JSValue::encode(v));
+ dataLogF("[r% 3d] | %10p | %-16s 0x%lld \n", registerCount, it, v.description(), (long long)JSValue::encode(v));
++it;
++registerCount;
} while (it != end);
}
- dataLog("-----------------------------------------------------------------------------\n");
+ dataLogF("-----------------------------------------------------------------------------\n");
}
#endif
diff --git a/Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp
new file mode 100644
index 000000000..73704aa03
--- /dev/null
+++ b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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 "ClosureCallStubRoutine.h"
+
+#if ENABLE(JIT)
+
+#include "Executable.h"
+#include "Heap.h"
+#include "JSGlobalData.h"
+#include "SlotVisitor.h"
+#include "Structure.h"
+
+namespace JSC {
+
+ClosureCallStubRoutine::ClosureCallStubRoutine(
+ const MacroAssemblerCodeRef& code, JSGlobalData& globalData, const JSCell* owner,
+ Structure* structure, ExecutableBase* executable, const CodeOrigin& codeOrigin)
+ : GCAwareJITStubRoutine(code, globalData, true)
+ , m_structure(globalData, owner, structure)
+ , m_executable(globalData, owner, executable)
+ , m_codeOrigin(codeOrigin)
+{
+}
+
+ClosureCallStubRoutine::~ClosureCallStubRoutine()
+{
+}
+
+void ClosureCallStubRoutine::markRequiredObjectsInternal(SlotVisitor& visitor)
+{
+ visitor.append(&m_structure);
+ visitor.append(&m_executable);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
+
diff --git a/Source/JavaScriptCore/jit/ClosureCallStubRoutine.h b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.h
new file mode 100644
index 000000000..3fd020691
--- /dev/null
+++ b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ClosureCallStubRoutine_h
+#define ClosureCallStubRoutine_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(JIT)
+
+#include "CodeOrigin.h"
+#include "GCAwareJITStubRoutine.h"
+
+namespace JSC {
+
+class ClosureCallStubRoutine : public GCAwareJITStubRoutine {
+public:
+ ClosureCallStubRoutine(
+ const MacroAssemblerCodeRef&, JSGlobalData&, const JSCell* owner,
+ Structure*, ExecutableBase*, const CodeOrigin&);
+
+ virtual ~ClosureCallStubRoutine();
+
+ Structure* structure() const { return m_structure.get(); }
+ ExecutableBase* executable() const { return m_executable.get(); }
+ const CodeOrigin& codeOrigin() const { return m_codeOrigin; }
+
+protected:
+ virtual void markRequiredObjectsInternal(SlotVisitor&);
+
+private:
+ WriteBarrier<Structure> m_structure;
+ WriteBarrier<ExecutableBase> m_executable;
+ // This allows us to figure out who a call is linked to by searching through
+ // stub routines.
+ CodeOrigin m_codeOrigin;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
+
+#endif // ClosureCallStubRoutine_h
+
diff --git a/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp b/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp
index 0f0eb14b7..521e49751 100644
--- a/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp
+++ b/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp
@@ -30,17 +30,17 @@
#include "Heap.h"
#include "JSGlobalData.h"
-
#include "SlotVisitor.h"
#include "Structure.h"
namespace JSC {
GCAwareJITStubRoutine::GCAwareJITStubRoutine(
- const MacroAssemblerCodeRef& code, JSGlobalData& globalData)
+ const MacroAssemblerCodeRef& code, JSGlobalData& globalData, bool isClosureCall)
: JITStubRoutine(code)
, m_mayBeExecuting(false)
, m_isJettisoned(false)
+ , m_isClosureCall(isClosureCall)
{
globalData.heap.m_jitStubRoutines.add(this);
}
diff --git a/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h b/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h
index 59bc76beb..e5ce281e8 100644
--- a/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h
+++ b/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h
@@ -54,7 +54,7 @@ class JITStubRoutineSet;
// list which does not get reclaimed all at once).
class GCAwareJITStubRoutine : public JITStubRoutine {
public:
- GCAwareJITStubRoutine(const MacroAssemblerCodeRef&, JSGlobalData&);
+ GCAwareJITStubRoutine(const MacroAssemblerCodeRef&, JSGlobalData&, bool isClosureCall = false);
virtual ~GCAwareJITStubRoutine();
void markRequiredObjects(SlotVisitor& visitor)
@@ -64,6 +64,8 @@ public:
void deleteFromGC();
+ bool isClosureCall() const { return m_isClosureCall; }
+
protected:
virtual void observeZeroRefCount();
@@ -74,6 +76,7 @@ private:
bool m_mayBeExecuting;
bool m_isJettisoned;
+ bool m_isClosureCall;
};
// Use this if you want to mark one additional object during GC if your stub
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..cccf33bf6 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"
@@ -212,6 +212,8 @@ void JIT::privateCompileMainPass()
m_callLinkInfoIndex = 0;
for (m_bytecodeOffset = 0; m_bytecodeOffset < instructionCount; ) {
+ if (m_disassembler)
+ m_disassembler->setForBytecodeMainPath(m_bytecodeOffset, label());
Instruction* currentInstruction = instructionsBegin + m_bytecodeOffset;
ASSERT_WITH_MESSAGE(m_interpreter->isOpcode(currentInstruction->u.opcode), "privateCompileMainPass gone bad @ %d", m_bytecodeOffset);
@@ -228,7 +230,7 @@ void JIT::privateCompileMainPass()
m_labels[m_bytecodeOffset] = label();
#if ENABLE(JIT_VERBOSE)
- dataLog("Old JIT emitting code for bc#%u at offset 0x%lx.\n", m_bytecodeOffset, (long)debugOffset());
+ dataLogF("Old JIT emitting code for bc#%u at offset 0x%lx.\n", m_bytecodeOffset, (long)debugOffset());
#endif
switch (m_interpreter->getOpcodeID(currentInstruction->u.opcode)) {
@@ -251,6 +253,7 @@ void JIT::privateCompileMainPass()
DEFINE_OP(op_call_varargs)
DEFINE_OP(op_catch)
DEFINE_OP(op_construct)
+ DEFINE_OP(op_get_callee)
DEFINE_OP(op_create_this)
DEFINE_OP(op_convert_this)
DEFINE_OP(op_init_lazy_reg)
@@ -448,8 +451,11 @@ void JIT::privateCompileSlowCases()
#endif
#if ENABLE(JIT_VERBOSE)
- dataLog("Old JIT emitting slow code for bc#%u at offset 0x%lx.\n", m_bytecodeOffset, (long)debugOffset());
+ dataLogF("Old JIT emitting slow code for bc#%u at offset 0x%lx.\n", m_bytecodeOffset, (long)debugOffset());
#endif
+
+ if (m_disassembler)
+ m_disassembler->setForBytecodeSlowPath(m_bytecodeOffset, label());
switch (m_interpreter->getOpcodeID(currentInstruction->u.opcode)) {
DEFINE_SLOWCASE_OP(op_add)
@@ -624,6 +630,12 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
break;
}
#endif
+
+ if (Options::showDisassembly())
+ m_disassembler = adoptPtr(new JITDisassembler(m_codeBlock));
+
+ if (m_disassembler)
+ m_disassembler->setStartOfCode(label());
// Just add a little bit of randomness to the codegen
if (m_randomGenerator.getUint32() & 1)
@@ -683,6 +695,9 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
privateCompileMainPass();
privateCompileLinkPass();
privateCompileSlowCases();
+
+ if (m_disassembler)
+ m_disassembler->setEndOfSlowPath(label());
Label arityCheck;
if (m_codeBlock->codeType() == FunctionCode) {
@@ -712,6 +727,9 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
}
ASSERT(m_jmpTable.isEmpty());
+
+ if (m_disassembler)
+ m_disassembler->setEndOfCode(label());
LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock, effort);
if (patchBuffer.didFailToAllocate())
@@ -780,10 +798,11 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
for (unsigned i = 0; i < m_codeBlock->numberOfCallLinkInfos(); ++i) {
CallLinkInfo& info = m_codeBlock->callLinkInfo(i);
info.callType = m_callStructureStubCompilationInfo[i].callType;
- info.bytecodeIndex = m_callStructureStubCompilationInfo[i].bytecodeIndex;
+ info.codeOrigin = CodeOrigin(m_callStructureStubCompilationInfo[i].bytecodeIndex);
info.callReturnLocation = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].callReturnLocation);
info.hotPathBegin = patchBuffer.locationOf(m_callStructureStubCompilationInfo[i].hotPathBegin);
info.hotPathOther = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].hotPathOther);
+ info.calleeGPR = regT0;
}
#if ENABLE(DFG_JIT) || ENABLE(LLINT)
@@ -803,11 +822,11 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
if (m_codeBlock->codeType() == FunctionCode && functionEntryArityCheck)
*functionEntryArityCheck = patchBuffer.locationOf(arityCheck);
+
+ if (m_disassembler)
+ m_disassembler->dump(patchBuffer);
- CodeRef result = FINALIZE_CODE(
- patchBuffer,
- ("Baseline JIT code for CodeBlock %p, instruction count = %u",
- m_codeBlock, m_codeBlock->instructionCount()));
+ CodeRef result = patchBuffer.finalizeCodeWithoutDisassembly();
m_globalData->machineCodeBytesPerBytecodeWordForBaselineJIT.add(
static_cast<double>(result.size()) /
@@ -816,7 +835,7 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
m_codeBlock->shrinkToFit(CodeBlock::LateShrink);
#if ENABLE(JIT_VERBOSE)
- dataLog("JIT generated code for %p at [%p, %p).\n", m_codeBlock, result.executableMemory()->start(), result.executableMemory()->end());
+ dataLogF("JIT generated code for %p at [%p, %p).\n", m_codeBlock, result.executableMemory()->start(), result.executableMemory()->end());
#endif
return JITCode(result, JITCode::BaselineJIT);
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index dcf87d352..c0d60add1 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -46,6 +46,7 @@
#include "CodeBlock.h"
#include "CompactJITCodeMap.h"
#include "Interpreter.h"
+#include "JITDisassembler.h"
#include "JSInterfaceJIT.h"
#include "Opcode.h"
#include "Profiler.h"
@@ -474,7 +475,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 +486,19 @@ 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(currentInstruction, badType, Int32Shape);
+ }
+ JumpList emitDoublePutByVal(Instruction* currentInstruction, PatchableJump& badType)
+ {
+ return emitGenericContiguousPutByVal(currentInstruction, badType, DoubleShape);
+ }
+ JumpList emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
+ {
+ return emitGenericContiguousPutByVal(currentInstruction, badType);
+ }
+ JumpList emitGenericContiguousPutByVal(Instruction*, PatchableJump& badType, IndexingType indexingShape = ContiguousShape);
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);
@@ -632,6 +647,7 @@ namespace JSC {
void emit_op_call_put_result(Instruction*);
void emit_op_catch(Instruction*);
void emit_op_construct(Instruction*);
+ void emit_op_get_callee(Instruction*);
void emit_op_create_this(Instruction*);
void emit_op_convert_this(Instruction*);
void emit_op_create_arguments(Instruction*);
@@ -930,6 +946,7 @@ namespace JSC {
int m_uninterruptedConstantSequenceBegin;
#endif
#endif
+ OwnPtr<JITDisassembler> m_disassembler;
WeakRandom m_randomGenerator;
static CodeRef stringGetByValStubGenerator(JSGlobalData*);
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/JITDisassembler.cpp b/Source/JavaScriptCore/jit/JITDisassembler.cpp
new file mode 100644
index 000000000..35b939913
--- /dev/null
+++ b/Source/JavaScriptCore/jit/JITDisassembler.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JITDisassembler.h"
+
+#if ENABLE(JIT)
+
+#include "CodeBlock.h"
+#include "JIT.h"
+
+namespace JSC {
+
+JITDisassembler::JITDisassembler(CodeBlock *codeBlock)
+ : m_codeBlock(codeBlock)
+ , m_labelForBytecodeIndexInMainPath(codeBlock->instructionCount())
+ , m_labelForBytecodeIndexInSlowPath(codeBlock->instructionCount())
+{
+}
+
+JITDisassembler::~JITDisassembler()
+{
+}
+
+void JITDisassembler::dump(LinkBuffer& linkBuffer)
+{
+ dataLogF("Baseline JIT code for CodeBlock %p, instruction count = %u:\n", m_codeBlock, m_codeBlock->instructionCount());
+ dataLogF(" Code at [%p, %p):\n", linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize());
+ dumpDisassembly(linkBuffer, m_startOfCode, m_labelForBytecodeIndexInMainPath[0]);
+
+ MacroAssembler::Label firstSlowLabel;
+ for (unsigned i = 0; i < m_labelForBytecodeIndexInSlowPath.size(); ++i) {
+ if (m_labelForBytecodeIndexInSlowPath[i].isSet()) {
+ firstSlowLabel = m_labelForBytecodeIndexInSlowPath[i];
+ break;
+ }
+ }
+ dumpForInstructions(linkBuffer, " ", m_labelForBytecodeIndexInMainPath, firstSlowLabel.isSet() ? firstSlowLabel : m_endOfSlowPath);
+ dataLogF(" (End Of Main Path)\n");
+ dumpForInstructions(linkBuffer, " (S) ", m_labelForBytecodeIndexInSlowPath, m_endOfSlowPath);
+ dataLogF(" (End Of Slow Path)\n");
+
+ dumpDisassembly(linkBuffer, m_endOfSlowPath, m_endOfCode);
+}
+
+void JITDisassembler::dumpForInstructions(LinkBuffer& linkBuffer, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel)
+{
+ for (unsigned i = 0 ; i < labels.size();) {
+ if (!labels[i].isSet()) {
+ i++;
+ continue;
+ }
+ dataLogF("%s", prefix);
+ m_codeBlock->dump(i);
+ for (unsigned nextIndex = i + 1; ; nextIndex++) {
+ if (nextIndex >= labels.size()) {
+ dumpDisassembly(linkBuffer, labels[i], endLabel);
+ return;
+ }
+ if (labels[nextIndex].isSet()) {
+ dumpDisassembly(linkBuffer, labels[i], labels[nextIndex]);
+ i = nextIndex;
+ break;
+ }
+ }
+ }
+}
+
+void JITDisassembler::dumpDisassembly(LinkBuffer& linkBuffer, MacroAssembler::Label from, MacroAssembler::Label to)
+{
+ CodeLocationLabel fromLocation = linkBuffer.locationOf(from);
+ CodeLocationLabel toLocation = linkBuffer.locationOf(to);
+ disassemble(fromLocation, bitwise_cast<uintptr_t>(toLocation.executableAddress()) - bitwise_cast<uintptr_t>(fromLocation.executableAddress()), " ", WTF::dataFile());
+}
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
+
diff --git a/Source/JavaScriptCore/jit/JITDisassembler.h b/Source/JavaScriptCore/jit/JITDisassembler.h
new file mode 100644
index 000000000..f8e917d98
--- /dev/null
+++ b/Source/JavaScriptCore/jit/JITDisassembler.h
@@ -0,0 +1,78 @@
+/*
+ * 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 JITDisassembler_h
+#define JITDisassembler_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(JIT)
+
+#include "LinkBuffer.h"
+#include "MacroAssembler.h"
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class CodeBlock;
+
+class JITDisassembler {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ JITDisassembler(CodeBlock*);
+ ~JITDisassembler();
+
+ void setStartOfCode(MacroAssembler::Label label) { m_startOfCode = label; }
+ void setForBytecodeMainPath(unsigned bytecodeIndex, MacroAssembler::Label label)
+ {
+ m_labelForBytecodeIndexInMainPath[bytecodeIndex] = label;
+ }
+ void setForBytecodeSlowPath(unsigned bytecodeIndex, MacroAssembler::Label label)
+ {
+ m_labelForBytecodeIndexInSlowPath[bytecodeIndex] = label;
+ }
+ void setEndOfSlowPath(MacroAssembler::Label label) { m_endOfSlowPath = label; }
+ void setEndOfCode(MacroAssembler::Label label) { m_endOfCode = label; }
+
+ void dump(LinkBuffer&);
+
+private:
+ void dumpForInstructions(LinkBuffer&, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel);
+ void dumpDisassembly(LinkBuffer&, MacroAssembler::Label from, MacroAssembler::Label to);
+
+ CodeBlock* m_codeBlock;
+ MacroAssembler::Label m_startOfCode;
+ Vector<MacroAssembler::Label> m_labelForBytecodeIndexInMainPath;
+ Vector<MacroAssembler::Label> m_labelForBytecodeIndexInSlowPath;
+ MacroAssembler::Label m_endOfSlowPath;
+ MacroAssembler::Label m_endOfCode;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
+
+#endif // JITDisassembler_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 4fb9d8cd5..9f0ce3a77 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"
@@ -1210,9 +1210,18 @@ void JIT::emit_op_convert_this(Instruction* currentInstruction)
addSlowCase(branchPtr(Equal, Address(regT1, JSCell::structureOffset()), TrustedImmPtr(m_globalData->stringStructure.get())));
}
-void JIT::emit_op_create_this(Instruction* currentInstruction)
+void JIT::emit_op_get_callee(Instruction* currentInstruction)
{
+ unsigned result = currentInstruction[1].u.operand;
emitGetFromCallFrameHeaderPtr(JSStack::Callee, regT0);
+ emitValueProfilingSite();
+ emitPutVirtualRegister(result);
+}
+
+void JIT::emit_op_create_this(Instruction* currentInstruction)
+{
+ int callee = currentInstruction[2].u.operand;
+ emitGetVirtualRegister(callee, regT0);
loadPtr(Address(regT0, JSFunction::offsetOfCachedInheritorID()), regT2);
addSlowCase(branchTestPtr(Zero, regT2));
@@ -1952,6 +1961,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 +1973,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 +1982,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..13daf962a 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"
@@ -1467,9 +1467,19 @@ void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction)
emitStore(dst, JSValue());
}
-void JIT::emit_op_create_this(Instruction* currentInstruction)
+void JIT::emit_op_get_callee(Instruction* currentInstruction)
{
+ int dst = currentInstruction[1].u.operand;
emitGetFromCallFrameHeaderPtr(JSStack::Callee, regT0);
+ move(TrustedImm32(JSValue::CellTag), regT1);
+ emitValueProfilingSite();
+ emitStore(dst, regT1, regT0);
+}
+
+void JIT::emit_op_create_this(Instruction* currentInstruction)
+{
+ int callee = currentInstruction[2].u.operand;
+ emitLoadPayload(callee, regT0);
loadPtr(Address(regT0, JSFunction::offsetOfCachedInheritorID()), regT2);
addSlowCase(branchTestPtr(Zero, regT2));
diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
index 6362598f4..57a5685eb 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,48 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
emitWriteBarrier(regT0, regT3, regT1, regT3, ShouldFilterImmediates, WriteBarrierForPropertyAccess);
}
-JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
+JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType, IndexingType indexingShape)
{
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 +445,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 +1374,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 +1443,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..be146a402 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,7 @@ 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)
+JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType, IndexingType indexingShape)
{
unsigned value = currentInstruction[3].u.operand;
ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
@@ -303,8 +331,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 +414,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/JITStubRoutine.h b/Source/JavaScriptCore/jit/JITStubRoutine.h
index a46fcfd1a..020ef6907 100644
--- a/Source/JavaScriptCore/jit/JITStubRoutine.h
+++ b/Source/JavaScriptCore/jit/JITStubRoutine.h
@@ -150,11 +150,11 @@ protected:
};
// Helper for the creation of simple stub routines that need no help from the GC.
-#define FINALIZE_CODE_FOR_STUB(patchBuffer, dataLogArguments) \
- (adoptRef(new JITStubRoutine(FINALIZE_CODE((patchBuffer), dataLogArguments))))
+#define FINALIZE_CODE_FOR_STUB(patchBuffer, dataLogFArguments) \
+ (adoptRef(new JITStubRoutine(FINALIZE_CODE((patchBuffer), dataLogFArguments))))
-#define FINALIZE_CODE_FOR_DFG_STUB(patchBuffer, dataLogArguments) \
- (adoptRef(new JITStubRoutine(FINALIZE_DFG_CODE((patchBuffer), dataLogArguments))))
+#define FINALIZE_CODE_FOR_DFG_STUB(patchBuffer, dataLogFArguments) \
+ (adoptRef(new JITStubRoutine(FINALIZE_DFG_CODE((patchBuffer), dataLogFArguments))))
} // namespace JSC
diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp
index 5ddb98dee..760ffd429 100644
--- a/Source/JavaScriptCore/jit/JITStubs.cpp
+++ b/Source/JavaScriptCore/jit/JITStubs.cpp
@@ -1808,12 +1808,12 @@ DEFINE_STUB_FUNCTION(void, optimize)
unsigned bytecodeIndex = stackFrame.args[0].int32();
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("%p: Entered optimize with bytecodeIndex = %u, executeCounter = %s, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, exitCounter = ", codeBlock, bytecodeIndex, codeBlock->jitExecuteCounter().status(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter());
+ dataLogF("%p: Entered optimize with bytecodeIndex = %u, executeCounter = %s, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, exitCounter = ", codeBlock, bytecodeIndex, codeBlock->jitExecuteCounter().status(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter());
if (codeBlock->hasOptimizedReplacement())
- dataLog("%u", codeBlock->replacement()->osrExitCounter());
+ dataLogF("%u", codeBlock->replacement()->osrExitCounter());
else
- dataLog("N/A");
- dataLog("\n");
+ dataLogF("N/A");
+ dataLogF("\n");
#endif
if (!codeBlock->checkIfOptimizationThresholdReached()) {
@@ -1823,7 +1823,7 @@ DEFINE_STUB_FUNCTION(void, optimize)
if (codeBlock->hasOptimizedReplacement()) {
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("Considering OSR into %p(%p).\n", codeBlock, codeBlock->replacement());
+ dataLogF("Considering OSR into %p(%p).\n", codeBlock, codeBlock->replacement());
#endif
// If we have an optimized replacement, then it must be the case that we entered
// cti_optimize from a loop. That's because is there's an optimized replacement,
@@ -1840,7 +1840,7 @@ DEFINE_STUB_FUNCTION(void, optimize)
// additional checking anyway, to reduce the amount of recompilation thrashing.
if (codeBlock->replacement()->shouldReoptimizeFromLoopNow()) {
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("Triggering reoptimization of %p(%p) (in loop).\n", codeBlock, codeBlock->replacement());
+ dataLogF("Triggering reoptimization of %p(%p) (in loop).\n", codeBlock, codeBlock->replacement());
#endif
codeBlock->reoptimize();
return;
@@ -1848,7 +1848,7 @@ DEFINE_STUB_FUNCTION(void, optimize)
} else {
if (!codeBlock->shouldOptimizeNow()) {
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("Delaying optimization for %p (in loop) because of insufficient profiling.\n", codeBlock);
+ dataLogF("Delaying optimization for %p (in loop) because of insufficient profiling.\n", codeBlock);
#endif
return;
}
@@ -1857,14 +1857,14 @@ DEFINE_STUB_FUNCTION(void, optimize)
JSObject* error = codeBlock->compileOptimized(callFrame, scope, bytecodeIndex);
#if ENABLE(JIT_VERBOSE_OSR)
if (error)
- dataLog("WARNING: optimized compilation failed.\n");
+ dataLogF("WARNING: optimized compilation failed.\n");
#else
UNUSED_PARAM(error);
#endif
if (codeBlock->replacement() == codeBlock) {
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("Optimizing %p failed.\n", codeBlock);
+ dataLogF("Optimizing %p failed.\n", codeBlock);
#endif
ASSERT(codeBlock->getJITType() == JITCode::BaselineJIT);
@@ -1877,8 +1877,13 @@ DEFINE_STUB_FUNCTION(void, optimize)
ASSERT(optimizedCodeBlock->getJITType() == JITCode::DFGJIT);
if (void* address = DFG::prepareOSREntry(callFrame, optimizedCodeBlock, bytecodeIndex)) {
+ if (Options::showDFGDisassembly()) {
+ dataLogF(
+ "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());
+ dataLogF("Optimizing %p succeeded, performing OSR after a delay of %u.\n", codeBlock, codeBlock->optimizationDelayCounter());
#endif
codeBlock->optimizeSoon();
@@ -1887,7 +1892,7 @@ DEFINE_STUB_FUNCTION(void, optimize)
}
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("Optimizing %p succeeded, OSR failed, after a delay of %u.\n", codeBlock, codeBlock->optimizationDelayCounter());
+ dataLogF("Optimizing %p succeeded, OSR failed, after a delay of %u.\n", codeBlock, codeBlock->optimizationDelayCounter());
#endif
// Count the OSR failure as a speculation failure. If this happens a lot, then
@@ -1895,7 +1900,7 @@ DEFINE_STUB_FUNCTION(void, optimize)
optimizedCodeBlock->countOSRExit();
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("Encountered OSR failure into %p(%p).\n", codeBlock, codeBlock->replacement());
+ dataLogF("Encountered OSR failure into %p(%p).\n", codeBlock, codeBlock->replacement());
#endif
// We are a lot more conservative about triggering reoptimization after OSR failure than
@@ -1908,7 +1913,7 @@ DEFINE_STUB_FUNCTION(void, optimize)
// reoptimization trigger.
if (optimizedCodeBlock->shouldReoptimizeNow()) {
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("Triggering reoptimization of %p(%p) (after OSR fail).\n", codeBlock, codeBlock->replacement());
+ dataLogF("Triggering reoptimization of %p(%p) (after OSR fail).\n", codeBlock, codeBlock->replacement());
#endif
codeBlock->reoptimize();
return;
@@ -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/jit/JumpReplacementWatchpoint.cpp b/Source/JavaScriptCore/jit/JumpReplacementWatchpoint.cpp
index 26eae57be..13270d4d3 100644
--- a/Source/JavaScriptCore/jit/JumpReplacementWatchpoint.cpp
+++ b/Source/JavaScriptCore/jit/JumpReplacementWatchpoint.cpp
@@ -47,7 +47,7 @@ void JumpReplacementWatchpoint::fireInternal()
void* source = bitwise_cast<void*>(m_source);
void* destination = bitwise_cast<void*>(m_destination);
if (Options::showDisassembly())
- dataLog("Firing jump replacement watchpoint from %p, to %p.\n", source, destination);
+ dataLogF("Firing jump replacement watchpoint from %p, to %p.\n", source, destination);
MacroAssembler::replaceWithJump(CodeLocationLabel(source), CodeLocationLabel(destination));
if (isOnList())
remove();
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/LLIntData.cpp b/Source/JavaScriptCore/llint/LLIntData.cpp
index eec376b37..90faff2ee 100644
--- a/Source/JavaScriptCore/llint/LLIntData.cpp
+++ b/Source/JavaScriptCore/llint/LLIntData.cpp
@@ -84,14 +84,14 @@ void Data::performAssertions(JSGlobalData& globalData)
ASSERT(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload) == 0);
#endif
#if USE(JSVALUE32_64)
- ASSERT(JSValue::Int32Tag == -1);
- ASSERT(JSValue::BooleanTag == -2);
- ASSERT(JSValue::NullTag == -3);
- ASSERT(JSValue::UndefinedTag == -4);
- ASSERT(JSValue::CellTag == -5);
- ASSERT(JSValue::EmptyValueTag == -6);
- ASSERT(JSValue::DeletedValueTag == -7);
- ASSERT(JSValue::LowestTag == -7);
+ ASSERT(JSValue::Int32Tag == static_cast<unsigned>(-1));
+ ASSERT(JSValue::BooleanTag == static_cast<unsigned>(-2));
+ ASSERT(JSValue::NullTag == static_cast<unsigned>(-3));
+ ASSERT(JSValue::UndefinedTag == static_cast<unsigned>(-4));
+ ASSERT(JSValue::CellTag == static_cast<unsigned>(-5));
+ ASSERT(JSValue::EmptyValueTag == static_cast<unsigned>(-6));
+ ASSERT(JSValue::DeletedValueTag == static_cast<unsigned>(-7));
+ ASSERT(JSValue::LowestTag == static_cast<unsigned>(-7));
#else
ASSERT(TagBitTypeOther == 0x2);
ASSERT(TagBitBool == 0x4);
diff --git a/Source/JavaScriptCore/llint/LLIntExceptions.cpp b/Source/JavaScriptCore/llint/LLIntExceptions.cpp
index 80ca732ad..5e6bba365 100644
--- a/Source/JavaScriptCore/llint/LLIntExceptions.cpp
+++ b/Source/JavaScriptCore/llint/LLIntExceptions.cpp
@@ -50,7 +50,7 @@ void interpreterThrowInCaller(ExecState* exec, ReturnAddressPtr pc)
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
#if LLINT_SLOW_PATH_TRACING
- dataLog("Throwing exception %s.\n", globalData->exception.description());
+ dataLogF("Throwing exception %s.\n", globalData->exception.description());
#endif
fixupPCforExceptionIfNeeded(exec);
genericThrow(
@@ -69,7 +69,7 @@ Instruction* returnToThrow(ExecState* exec, Instruction* pc)
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
#if LLINT_SLOW_PATH_TRACING
- dataLog("Throwing exception %s (returnToThrow).\n", globalData->exception.description());
+ dataLogF("Throwing exception %s (returnToThrow).\n", globalData->exception.description());
#endif
fixupPCforExceptionIfNeeded(exec);
genericThrow(globalData, exec, globalData->exception, pc - exec->codeBlock()->instructions().begin());
@@ -82,7 +82,7 @@ void* callToThrow(ExecState* exec, Instruction* pc)
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
#if LLINT_SLOW_PATH_TRACING
- dataLog("Throwing exception %s (callToThrow).\n", globalData->exception.description());
+ dataLogF("Throwing exception %s (callToThrow).\n", globalData->exception.description());
#endif
fixupPCforExceptionIfNeeded(exec);
genericThrow(globalData, exec, globalData->exception, pc - exec->codeBlock()->instructions().begin());
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
index ba44bf404..584100e50 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
@@ -162,7 +162,7 @@ namespace JSC { namespace LLInt {
extern "C" SlowPathReturnType llint_trace_operand(ExecState* exec, Instruction* pc, int fromWhere, int operand)
{
LLINT_BEGIN();
- dataLog("%p / %p: executing bc#%zu, op#%u: Trace(%d): %d: %d\n",
+ dataLogF("%p / %p: executing bc#%zu, op#%u: Trace(%d): %d: %d\n",
exec->codeBlock(),
exec,
static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()),
@@ -184,7 +184,7 @@ extern "C" SlowPathReturnType llint_trace_value(ExecState* exec, Instruction* pc
EncodedJSValue asValue;
} u;
u.asValue = JSValue::encode(value);
- dataLog("%p / %p: executing bc#%zu, op#%u: Trace(%d): %d: %d: %08x:%08x: %s\n",
+ dataLogF("%p / %p: executing bc#%zu, op#%u: Trace(%d): %d: %d: %08x:%08x: %s\n",
exec->codeBlock(),
exec,
static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()),
@@ -200,7 +200,7 @@ extern "C" SlowPathReturnType llint_trace_value(ExecState* exec, Instruction* pc
LLINT_SLOW_PATH_DECL(trace_prologue)
{
- dataLog("%p / %p: in prologue.\n", exec->codeBlock(), exec);
+ dataLogF("%p / %p: in prologue.\n", exec->codeBlock(), exec);
LLINT_END_IMPL();
}
@@ -209,7 +209,7 @@ static void traceFunctionPrologue(ExecState* exec, const char* comment, CodeSpec
JSFunction* callee = jsCast<JSFunction*>(exec->callee());
FunctionExecutable* executable = callee->jsExecutable();
CodeBlock* codeBlock = &executable->generatedBytecodeFor(kind);
- dataLog("%p / %p: in %s of function %p, executable %p; numVars = %u, numParameters = %u, numCalleeRegisters = %u, caller = %p.\n",
+ dataLogF("%p / %p: in %s of function %p, executable %p; numVars = %u, numParameters = %u, numCalleeRegisters = %u, caller = %p.\n",
codeBlock, exec, comment, callee, executable,
codeBlock->m_numVars, codeBlock->numParameters(), codeBlock->m_numCalleeRegisters,
exec->callerFrame());
@@ -241,22 +241,22 @@ LLINT_SLOW_PATH_DECL(trace_arityCheck_for_construct)
LLINT_SLOW_PATH_DECL(trace)
{
- dataLog("%p / %p: executing bc#%zu, %s, scope %p\n",
+ dataLogF("%p / %p: executing bc#%zu, %s, scope %p\n",
exec->codeBlock(),
exec,
static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()),
opcodeNames[exec->globalData().interpreter->getOpcodeID(pc[0].u.opcode)],
exec->scope());
if (exec->globalData().interpreter->getOpcodeID(pc[0].u.opcode) == op_ret) {
- dataLog("Will be returning to %p\n", exec->returnPC().value());
- dataLog("The new cfr will be %p\n", exec->callerFrame());
+ dataLogF("Will be returning to %p\n", exec->returnPC().value());
+ dataLogF("The new cfr will be %p\n", exec->callerFrame());
}
LLINT_END_IMPL();
}
LLINT_SLOW_PATH_DECL(special_trace)
{
- dataLog("%p / %p: executing special case bc#%zu, op#%u, return PC is %p\n",
+ dataLogF("%p / %p: executing special case bc#%zu, op#%u, return PC is %p\n",
exec->codeBlock(),
exec,
static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()),
@@ -275,11 +275,11 @@ 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)
- dataLog(" JIT threshold should be lifted.\n");
+ dataLogF(" JIT threshold should be lifted.\n");
#endif
return false;
}
@@ -288,19 +288,19 @@ inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec)
switch (result) {
case CodeBlock::AlreadyCompiled:
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog(" Code was already compiled.\n");
+ dataLogF(" Code was already compiled.\n");
#endif
codeBlock->jitSoon();
return true;
case CodeBlock::CouldNotCompile:
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog(" JIT compilation failed.\n");
+ dataLogF(" JIT compilation failed.\n");
#endif
codeBlock->dontJITAnytimeSoon();
return false;
case CodeBlock::CompiledSuccessfully:
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog(" JIT compilation successful.\n");
+ dataLogF(" JIT compilation successful.\n");
#endif
codeBlock->jitSoon();
return true;
@@ -313,7 +313,7 @@ enum EntryKind { Prologue, ArityCheck };
static SlowPathReturnType entryOSR(ExecState* exec, Instruction*, CodeBlock* codeBlock, const char *name, EntryKind kind)
{
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("%p: Entered %s with executeCounter = %s\n", codeBlock, name,
+ dataLogF("%p: Entered %s with executeCounter = %s\n", codeBlock, name,
codeBlock->llintExecuteCounter().status());
#else
UNUSED_PARAM(name);
@@ -362,7 +362,7 @@ LLINT_SLOW_PATH_DECL(loop_osr)
CodeBlock* codeBlock = exec->codeBlock();
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("%p: Entered loop_osr with executeCounter = %s\n", codeBlock,
+ dataLogF("%p: Entered loop_osr with executeCounter = %s\n", codeBlock,
codeBlock->llintExecuteCounter().status());
#endif
@@ -393,7 +393,7 @@ LLINT_SLOW_PATH_DECL(replace)
CodeBlock* codeBlock = exec->codeBlock();
#if ENABLE(JIT_VERBOSE_OSR)
- dataLog("%p: Entered replace with executeCounter = %s\n", codeBlock,
+ dataLogF("%p: Entered replace with executeCounter = %s\n", codeBlock,
codeBlock->llintExecuteCounter().status());
#endif
@@ -409,11 +409,11 @@ LLINT_SLOW_PATH_DECL(stack_check)
{
LLINT_BEGIN();
#if LLINT_SLOW_PATH_TRACING
- dataLog("Checking stack height with exec = %p.\n", exec);
- dataLog("CodeBlock = %p.\n", exec->codeBlock());
- dataLog("Num callee registers = %u.\n", exec->codeBlock()->m_numCalleeRegisters);
- dataLog("Num vars = %u.\n", exec->codeBlock()->m_numVars);
- dataLog("Current end is at %p.\n", exec->globalData().interpreter->stack().end());
+ dataLogF("Checking stack height with exec = %p.\n", exec);
+ dataLogF("CodeBlock = %p.\n", exec->codeBlock());
+ dataLogF("Num callee registers = %u.\n", exec->codeBlock()->m_numCalleeRegisters);
+ dataLogF("Num vars = %u.\n", exec->codeBlock()->m_numVars);
+ dataLogF("Current end is at %p.\n", exec->globalData().interpreter->stack().end());
#endif
ASSERT(&exec->registers()[exec->codeBlock()->m_numCalleeRegisters] > exec->globalData().interpreter->stack().end());
if (UNLIKELY(!globalData.interpreter->stack().grow(&exec->registers()[exec->codeBlock()->m_numCalleeRegisters]))) {
@@ -458,7 +458,7 @@ LLINT_SLOW_PATH_DECL(slow_path_create_activation)
{
LLINT_BEGIN();
#if LLINT_SLOW_PATH_TRACING
- dataLog("Creating an activation, exec = %p!\n", exec);
+ dataLogF("Creating an activation, exec = %p!\n", exec);
#endif
JSActivation* activation = JSActivation::create(globalData, exec, exec->codeBlock());
exec->setScope(activation);
@@ -478,7 +478,7 @@ LLINT_SLOW_PATH_DECL(slow_path_create_arguments)
LLINT_SLOW_PATH_DECL(slow_path_create_this)
{
LLINT_BEGIN();
- JSFunction* constructor = jsCast<JSFunction*>(exec->callee());
+ JSFunction* constructor = jsCast<JSFunction*>(LLINT_OP(2).jsValue().asCell());
#if !ASSERT_DISABLED
ConstructData constructData;
@@ -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)
@@ -635,8 +635,8 @@ LLINT_SLOW_PATH_DECL(slow_path_add)
JSValue v2 = LLINT_OP_C(3).jsValue();
#if LLINT_SLOW_PATH_TRACING
- dataLog("Trying to add %s", v1.description());
- dataLog(" to %s.\n", v2.description());
+ dataLogF("Trying to add %s", v1.description());
+ dataLogF(" to %s.\n", v2.description());
#endif
if (v1.isString() && !v2.isObject())
@@ -1328,7 +1328,7 @@ LLINT_SLOW_PATH_DECL(slow_path_new_func)
|| !codeBlock->needsFullScopeChain()
|| exec->uncheckedR(codeBlock->activationRegister()).jsValue());
#if LLINT_SLOW_PATH_TRACING
- dataLog("Creating function!\n");
+ dataLogF("Creating function!\n");
#endif
LLINT_RETURN(JSFunction::create(exec, codeBlock->functionDecl(pc[2].u.operand), exec->scope()));
}
@@ -1367,7 +1367,7 @@ static SlowPathReturnType handleHostCall(ExecState* execCallee, Instruction* pc,
}
#if LLINT_SLOW_PATH_TRACING
- dataLog("Call callee is not a function: %s\n", callee.description());
+ dataLogF("Call callee is not a function: %s\n", callee.description());
#endif
ASSERT(callType == CallTypeNone);
@@ -1390,7 +1390,7 @@ static SlowPathReturnType handleHostCall(ExecState* execCallee, Instruction* pc,
}
#if LLINT_SLOW_PATH_TRACING
- dataLog("Constructor callee is not a function: %s\n", callee.description());
+ dataLogF("Constructor callee is not a function: %s\n", callee.description());
#endif
ASSERT(constructType == ConstructTypeNone);
@@ -1400,7 +1400,7 @@ static SlowPathReturnType handleHostCall(ExecState* execCallee, Instruction* pc,
inline SlowPathReturnType setUpCall(ExecState* execCallee, Instruction* pc, CodeSpecializationKind kind, JSValue calleeAsValue, LLIntCallLinkInfo* callLinkInfo = 0)
{
#if LLINT_SLOW_PATH_TRACING
- dataLog("Performing call with recorded PC = %p\n", execCallee->callerFrame()->currentVPC());
+ dataLogF("Performing call with recorded PC = %p\n", execCallee->callerFrame()->currentVPC());
#endif
JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
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..8d5cdf108 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -349,18 +349,30 @@ _llint_op_create_arguments:
_llint_op_create_this:
traceExecution()
- loadp Callee[cfr], t0
+ loadi 8[PC], t0
+ loadp PayloadOffset[cfr, t0, 8], t0
loadp JSFunction::m_cachedInheritorID[t0], t2
btpz t2, .opCreateThisSlow
allocateBasicJSObject(JSFinalObjectSizeClassIndex, t2, t0, t1, t3, .opCreateThisSlow)
loadi 4[PC], t1
storei CellTag, TagOffset[cfr, t1, 8]
storei t0, PayloadOffset[cfr, t1, 8]
- dispatch(2)
+ dispatch(3)
.opCreateThisSlow:
callSlowPath(_llint_slow_path_create_this)
- dispatch(2)
+ dispatch(3)
+
+
+_llint_op_get_callee:
+ traceExecution()
+ loadi 4[PC], t0
+ loadp PayloadOffset + Callee[cfr], t1
+ loadp 8[PC], t2
+ valueProfile(CellTag, t1, t2)
+ storei CellTag, TagOffset[cfr, t0, 8]
+ storei t1, PayloadOffset[cfr, t0, 8]
+ dispatch(3)
_llint_op_convert_this:
@@ -1185,7 +1197,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 +1207,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 +1226,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 +1295,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 +1324,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..ed6799ef3 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
@@ -241,17 +241,28 @@ _llint_op_create_arguments:
_llint_op_create_this:
traceExecution()
- loadp Callee[cfr], t0
+ loadisFromInstruction(2, t0)
+ loadp [cfr, t0, 8], t0
loadp JSFunction::m_cachedInheritorID[t0], t2
btpz t2, .opCreateThisSlow
allocateBasicJSObject(JSFinalObjectSizeClassIndex, t2, t0, t1, t3, .opCreateThisSlow)
loadisFromInstruction(1, t1)
storeq t0, [cfr, t1, 8]
- dispatch(2)
+ dispatch(3)
.opCreateThisSlow:
callSlowPath(_llint_slow_path_create_this)
- dispatch(2)
+ dispatch(3)
+
+
+_llint_op_get_callee:
+ traceExecution()
+ loadisFromInstruction(1, t0)
+ loadpFromInstruction(2, t2)
+ loadp Callee[cfr], t1
+ valueProfile(t1, t2)
+ storep t1, [cfr, t0, 8]
+ dispatch(3)
_llint_op_convert_this:
@@ -1025,7 +1036,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 +1047,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 +1132,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 +1162,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/profiler/Profile.cpp b/Source/JavaScriptCore/profiler/Profile.cpp
index a641580ec..2274889a1 100644
--- a/Source/JavaScriptCore/profiler/Profile.cpp
+++ b/Source/JavaScriptCore/profiler/Profile.cpp
@@ -103,7 +103,7 @@ void Profile::restoreAll()
#ifndef NDEBUG
void Profile::debugPrintData() const
{
- dataLog("Call graph:\n");
+ dataLogF("Call graph:\n");
m_head->debugPrintData(0);
}
@@ -119,18 +119,18 @@ void Profile::debugPrintDataSampleStyle() const
typedef Vector<NameCountPair> NameCountPairVector;
FunctionCallHashCount countedFunctions;
- dataLog("Call graph:\n");
+ dataLogF("Call graph:\n");
m_head->debugPrintDataSampleStyle(0, countedFunctions);
- dataLog("\nTotal number in stack:\n");
+ dataLogF("\nTotal number in stack:\n");
NameCountPairVector sortedFunctions(countedFunctions.size());
copyToVector(countedFunctions, sortedFunctions);
std::sort(sortedFunctions.begin(), sortedFunctions.end(), functionNameCountPairComparator);
for (NameCountPairVector::iterator it = sortedFunctions.begin(); it != sortedFunctions.end(); ++it)
- dataLog(" %-12d%s\n", (*it).value, String((*it).key).utf8().data());
+ dataLogF(" %-12d%s\n", (*it).value, String((*it).key).utf8().data());
- dataLog("\nSort by top of stack, same collapsed (when >= 5):\n");
+ dataLogF("\nSort by top of stack, same collapsed (when >= 5):\n");
}
#endif
diff --git a/Source/JavaScriptCore/profiler/ProfileNode.cpp b/Source/JavaScriptCore/profiler/ProfileNode.cpp
index ab43d1511..6c36e47d0 100644
--- a/Source/JavaScriptCore/profiler/ProfileNode.cpp
+++ b/Source/JavaScriptCore/profiler/ProfileNode.cpp
@@ -294,9 +294,9 @@ void ProfileNode::debugPrintData(int indentLevel) const
{
// Print function names
for (int i = 0; i < indentLevel; ++i)
- dataLog(" ");
+ dataLogF(" ");
- dataLog("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
+ dataLogF("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
functionName().utf8().data(),
m_numberOfCalls, m_actualSelfTime, selfPercent(), m_actualTotalTime, totalPercent(),
m_visibleSelfTime, m_visibleTotalTime,
@@ -313,20 +313,20 @@ void ProfileNode::debugPrintData(int indentLevel) const
// print the profiled data in a format that matches the tool sample's output.
double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const
{
- dataLog(" ");
+ dataLogF(" ");
// Print function names
const char* name = functionName().utf8().data();
double sampleCount = m_actualTotalTime * 1000;
if (indentLevel) {
for (int i = 0; i < indentLevel; ++i)
- dataLog(" ");
+ dataLogF(" ");
countedFunctions.add(functionName().impl());
- dataLog("%.0f %s\n", sampleCount ? sampleCount : 1, name);
+ dataLogF("%.0f %s\n", sampleCount ? sampleCount : 1, name);
} else
- dataLog("%s\n", name);
+ dataLogF("%s\n", name);
++indentLevel;
@@ -338,11 +338,11 @@ double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashC
sumOfChildrensCount *= 1000; //
// Print remainder of samples to match sample's output
if (sumOfChildrensCount < sampleCount) {
- dataLog(" ");
+ dataLogF(" ");
while (indentLevel--)
- dataLog(" ");
+ dataLogF(" ");
- dataLog("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data());
+ dataLogF("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data());
}
return m_actualTotalTime;
diff --git a/Source/JavaScriptCore/profiler/ProfileNode.h b/Source/JavaScriptCore/profiler/ProfileNode.h
index 26000a827..f5fef86f8 100644
--- a/Source/JavaScriptCore/profiler/ProfileNode.h
+++ b/Source/JavaScriptCore/profiler/ProfileNode.h
@@ -64,6 +64,7 @@ namespace JSC {
// CallIdentifier members
ExecState* callerCallFrame() const { return m_callerCallFrame; }
const CallIdentifier& callIdentifier() const { return m_callIdentifier; }
+ unsigned long callUID() const { return m_callIdentifier.hash(); };
const String& functionName() const { return m_callIdentifier.m_name; }
const String& url() const { return m_callIdentifier.m_url; }
unsigned lineNumber() const { return m_callIdentifier.m_lineNumber; }
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..e6d37fb02 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"
@@ -116,15 +116,14 @@ const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, 0, ExecStat
ArrayPrototype* ArrayPrototype::create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
{
- Butterfly* butterfly = createArrayButterfly(exec->globalData(), 0);
- ArrayPrototype* prototype = new (NotNull, allocateCell<ArrayPrototype>(*exec->heap())) ArrayPrototype(globalObject, structure, butterfly);
+ ArrayPrototype* prototype = new (NotNull, allocateCell<ArrayPrototype>(*exec->heap())) ArrayPrototype(globalObject, structure);
prototype->finishCreation(globalObject);
return prototype;
}
// ECMA 15.4.4
-ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure, Butterfly* butterfly)
- : JSArray(globalObject->globalData(), structure, butterfly)
+ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure)
+ : JSArray(globalObject->globalData(), structure, 0)
{
}
@@ -456,7 +455,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 +617,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 +732,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 +747,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 +819,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 +879,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..c23bcdec1 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*);
- 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, ArrayClass);
+ }
- protected:
- void finishCreation(JSGlobalObject*);
- };
+protected:
+ void finishCreation(JSGlobalObject*);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
index 610b8d16c..178bf3fe9 100644
--- a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
+++ b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
@@ -31,25 +31,25 @@
namespace JSC {
- class BatchedTransitionOptimizer {
- WTF_MAKE_NONCOPYABLE(BatchedTransitionOptimizer);
- public:
- BatchedTransitionOptimizer(JSGlobalData& globalData, JSObject* object)
- : m_globalData(&globalData)
- , m_object(object)
- {
- }
-
- ~BatchedTransitionOptimizer()
- {
- if (m_object->structure()->isDictionary())
- m_object->flattenDictionaryObject(*m_globalData);
- }
-
- private:
- JSGlobalData* m_globalData;
- JSObject* m_object;
- };
+class BatchedTransitionOptimizer {
+ WTF_MAKE_NONCOPYABLE(BatchedTransitionOptimizer);
+public:
+ BatchedTransitionOptimizer(JSGlobalData& globalData, JSObject* object)
+ : m_globalData(&globalData)
+ , m_object(object)
+ {
+ }
+
+ ~BatchedTransitionOptimizer()
+ {
+ if (m_object->structure()->isDictionary())
+ m_object->flattenDictionaryObject(*m_globalData);
+ }
+
+private:
+ JSGlobalData* m_globalData;
+ JSObject* m_object;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.h b/Source/JavaScriptCore/runtime/BooleanConstructor.h
index 2b6bafa2f..f395374ae 100644
--- a/Source/JavaScriptCore/runtime/BooleanConstructor.h
+++ b/Source/JavaScriptCore/runtime/BooleanConstructor.h
@@ -25,37 +25,37 @@
namespace JSC {
- class BooleanPrototype;
+class BooleanPrototype;
- class BooleanConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
+class BooleanConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
- static BooleanConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, BooleanPrototype* booleanPrototype)
- {
- BooleanConstructor* constructor = new (NotNull, allocateCell<BooleanConstructor>(*exec->heap())) BooleanConstructor(globalObject, structure);
- constructor->finishCreation(exec, booleanPrototype);
- return constructor;
- }
+ static BooleanConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, BooleanPrototype* booleanPrototype)
+ {
+ BooleanConstructor* constructor = new (NotNull, allocateCell<BooleanConstructor>(*exec->heap())) BooleanConstructor(globalObject, structure);
+ constructor->finishCreation(exec, booleanPrototype);
+ 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*, BooleanPrototype*);
+protected:
+ void finishCreation(ExecState*, BooleanPrototype*);
- private:
- BooleanConstructor(JSGlobalObject*, Structure*);
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
- };
+private:
+ BooleanConstructor(JSGlobalObject*, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
- JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSGlobalObject*, JSValue);
- JSObject* constructBoolean(ExecState*, const ArgList&);
+JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSGlobalObject*, JSValue);
+JSObject* constructBoolean(ExecState*, const ArgList&);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BooleanObject.h b/Source/JavaScriptCore/runtime/BooleanObject.h
index bd0f66944..b6fcccdcf 100644
--- a/Source/JavaScriptCore/runtime/BooleanObject.h
+++ b/Source/JavaScriptCore/runtime/BooleanObject.h
@@ -25,36 +25,36 @@
namespace JSC {
- class BooleanObject : public JSWrapperObject {
- protected:
- JS_EXPORT_PRIVATE BooleanObject(JSGlobalData&, Structure*);
- JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&);
-
- public:
- typedef JSWrapperObject Base;
-
- static BooleanObject* create(JSGlobalData& globalData, Structure* structure)
- {
- BooleanObject* boolean = new (NotNull, allocateCell<BooleanObject>(globalData.heap)) BooleanObject(globalData, structure);
- boolean->finishCreation(globalData);
- return boolean;
- }
-
- static JS_EXPORTDATA const ClassInfo s_info;
-
- static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
- }
- };
+class BooleanObject : public JSWrapperObject {
+protected:
+ JS_EXPORT_PRIVATE BooleanObject(JSGlobalData&, Structure*);
+ JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&);
- BooleanObject* asBooleanObject(JSValue);
+public:
+ typedef JSWrapperObject Base;
- inline BooleanObject* asBooleanObject(JSValue value)
+ static BooleanObject* create(JSGlobalData& globalData, Structure* structure)
+ {
+ BooleanObject* boolean = new (NotNull, allocateCell<BooleanObject>(globalData.heap)) BooleanObject(globalData, structure);
+ boolean->finishCreation(globalData);
+ return boolean;
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
{
- ASSERT(asObject(value)->inherits(&BooleanObject::s_info));
- return static_cast<BooleanObject*>(asObject(value));
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
}
+};
+
+BooleanObject* asBooleanObject(JSValue);
+
+inline BooleanObject* asBooleanObject(JSValue value)
+{
+ ASSERT(asObject(value)->inherits(&BooleanObject::s_info));
+ return static_cast<BooleanObject*>(asObject(value));
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.h b/Source/JavaScriptCore/runtime/BooleanPrototype.h
index 3767f76ed..05790a755 100644
--- a/Source/JavaScriptCore/runtime/BooleanPrototype.h
+++ b/Source/JavaScriptCore/runtime/BooleanPrototype.h
@@ -25,34 +25,34 @@
namespace JSC {
- class BooleanPrototype : public BooleanObject {
- public:
- typedef BooleanObject Base;
-
- static BooleanPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
- {
- BooleanPrototype* prototype = new (NotNull, allocateCell<BooleanPrototype>(*exec->heap())) BooleanPrototype(exec, structure);
- prototype->finishCreation(exec, globalObject);
- return prototype;
- }
+class BooleanPrototype : public BooleanObject {
+public:
+ typedef BooleanObject Base;
+
+ static BooleanPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ BooleanPrototype* prototype = new (NotNull, allocateCell<BooleanPrototype>(*exec->heap())) BooleanPrototype(exec, structure);
+ prototype->finishCreation(exec, globalObject);
+ return prototype;
+ }
- 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*, JSGlobalObject*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | BooleanObject::StructureFlags;
+protected:
+ void finishCreation(ExecState*, JSGlobalObject*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | BooleanObject::StructureFlags;
- private:
- BooleanPrototype(ExecState*, Structure*);
- static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
+private:
+ BooleanPrototype(ExecState*, Structure*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
- static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
- };
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+};
} // 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/CallData.h b/Source/JavaScriptCore/runtime/CallData.h
index 77478304c..7df36c72a 100644
--- a/Source/JavaScriptCore/runtime/CallData.h
+++ b/Source/JavaScriptCore/runtime/CallData.h
@@ -33,31 +33,31 @@
namespace JSC {
- class ArgList;
- class ExecState;
- class FunctionExecutable;
- class JSObject;
- class JSScope;
+class ArgList;
+class ExecState;
+class FunctionExecutable;
+class JSObject;
+class JSScope;
- enum CallType {
- CallTypeNone,
- CallTypeHost,
- CallTypeJS
- };
+enum CallType {
+ CallTypeNone,
+ CallTypeHost,
+ CallTypeJS
+};
- typedef EncodedJSValue (JSC_HOST_CALL *NativeFunction)(ExecState*);
+typedef EncodedJSValue (JSC_HOST_CALL *NativeFunction)(ExecState*);
- union CallData {
- struct {
- NativeFunction function;
- } native;
- struct {
- FunctionExecutable* functionExecutable;
- JSScope* scope;
- } js;
- };
+union CallData {
+ struct {
+ NativeFunction function;
+ } native;
+ struct {
+ FunctionExecutable* functionExecutable;
+ JSScope* scope;
+ } js;
+};
- JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&);
+JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h
index c918621fe..af1d71e13 100644
--- a/Source/JavaScriptCore/runtime/ClassInfo.h
+++ b/Source/JavaScriptCore/runtime/ClassInfo.h
@@ -29,90 +29,90 @@
namespace JSC {
- class HashEntry;
- struct HashTable;
+class HashEntry;
+struct HashTable;
- struct MethodTable {
- typedef void (*DestroyFunctionPtr)(JSCell*);
- DestroyFunctionPtr destroy;
+struct MethodTable {
+ typedef void (*DestroyFunctionPtr)(JSCell*);
+ DestroyFunctionPtr destroy;
- typedef void (*VisitChildrenFunctionPtr)(JSCell*, SlotVisitor&);
- VisitChildrenFunctionPtr visitChildren;
+ typedef void (*VisitChildrenFunctionPtr)(JSCell*, SlotVisitor&);
+ VisitChildrenFunctionPtr visitChildren;
- typedef void (*CopyBackingStoreFunctionPtr)(JSCell*, CopyVisitor&);
- CopyBackingStoreFunctionPtr copyBackingStore;
+ typedef void (*CopyBackingStoreFunctionPtr)(JSCell*, CopyVisitor&);
+ CopyBackingStoreFunctionPtr copyBackingStore;
- typedef CallType (*GetCallDataFunctionPtr)(JSCell*, CallData&);
- GetCallDataFunctionPtr getCallData;
+ typedef CallType (*GetCallDataFunctionPtr)(JSCell*, CallData&);
+ GetCallDataFunctionPtr getCallData;
- typedef ConstructType (*GetConstructDataFunctionPtr)(JSCell*, ConstructData&);
- GetConstructDataFunctionPtr getConstructData;
+ typedef ConstructType (*GetConstructDataFunctionPtr)(JSCell*, ConstructData&);
+ GetConstructDataFunctionPtr getConstructData;
- typedef void (*PutFunctionPtr)(JSCell*, ExecState*, PropertyName propertyName, JSValue, PutPropertySlot&);
- PutFunctionPtr put;
+ typedef void (*PutFunctionPtr)(JSCell*, ExecState*, PropertyName propertyName, JSValue, PutPropertySlot&);
+ PutFunctionPtr put;
- typedef void (*PutByIndexFunctionPtr)(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
- PutByIndexFunctionPtr putByIndex;
+ typedef void (*PutByIndexFunctionPtr)(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
+ PutByIndexFunctionPtr putByIndex;
- typedef bool (*DeletePropertyFunctionPtr)(JSCell*, ExecState*, PropertyName);
- DeletePropertyFunctionPtr deleteProperty;
+ typedef bool (*DeletePropertyFunctionPtr)(JSCell*, ExecState*, PropertyName);
+ DeletePropertyFunctionPtr deleteProperty;
- typedef bool (*DeletePropertyByIndexFunctionPtr)(JSCell*, ExecState*, unsigned);
- DeletePropertyByIndexFunctionPtr deletePropertyByIndex;
+ typedef bool (*DeletePropertyByIndexFunctionPtr)(JSCell*, ExecState*, unsigned);
+ DeletePropertyByIndexFunctionPtr deletePropertyByIndex;
- typedef bool (*GetOwnPropertySlotFunctionPtr)(JSCell*, ExecState*, PropertyName, PropertySlot&);
- GetOwnPropertySlotFunctionPtr getOwnPropertySlot;
+ typedef bool (*GetOwnPropertySlotFunctionPtr)(JSCell*, ExecState*, PropertyName, PropertySlot&);
+ GetOwnPropertySlotFunctionPtr getOwnPropertySlot;
- typedef bool (*GetOwnPropertySlotByIndexFunctionPtr)(JSCell*, ExecState*, unsigned, PropertySlot&);
- GetOwnPropertySlotByIndexFunctionPtr getOwnPropertySlotByIndex;
+ typedef bool (*GetOwnPropertySlotByIndexFunctionPtr)(JSCell*, ExecState*, unsigned, PropertySlot&);
+ GetOwnPropertySlotByIndexFunctionPtr getOwnPropertySlotByIndex;
- typedef JSObject* (*ToThisObjectFunctionPtr)(JSCell*, ExecState*);
- ToThisObjectFunctionPtr toThisObject;
+ typedef JSObject* (*ToThisObjectFunctionPtr)(JSCell*, ExecState*);
+ ToThisObjectFunctionPtr toThisObject;
- typedef JSValue (*DefaultValueFunctionPtr)(const JSObject*, ExecState*, PreferredPrimitiveType);
- DefaultValueFunctionPtr defaultValue;
+ typedef JSValue (*DefaultValueFunctionPtr)(const JSObject*, ExecState*, PreferredPrimitiveType);
+ DefaultValueFunctionPtr defaultValue;
- typedef void (*GetOwnPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- GetOwnPropertyNamesFunctionPtr getOwnPropertyNames;
+ typedef void (*GetOwnPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ GetOwnPropertyNamesFunctionPtr getOwnPropertyNames;
- typedef void (*GetOwnNonIndexPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- GetOwnNonIndexPropertyNamesFunctionPtr getOwnNonIndexPropertyNames;
+ typedef void (*GetOwnNonIndexPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ GetOwnNonIndexPropertyNamesFunctionPtr getOwnNonIndexPropertyNames;
- typedef void (*GetPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- GetPropertyNamesFunctionPtr getPropertyNames;
+ typedef void (*GetPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ GetPropertyNamesFunctionPtr getPropertyNames;
- typedef String (*ClassNameFunctionPtr)(const JSObject*);
- ClassNameFunctionPtr className;
+ typedef String (*ClassNameFunctionPtr)(const JSObject*);
+ ClassNameFunctionPtr className;
- typedef bool (*CustomHasInstanceFunctionPtr)(JSObject*, ExecState*, JSValue);
- CustomHasInstanceFunctionPtr customHasInstance;
+ typedef bool (*CustomHasInstanceFunctionPtr)(JSObject*, ExecState*, JSValue);
+ CustomHasInstanceFunctionPtr customHasInstance;
- typedef void (*PutWithAttributesFunctionPtr)(JSObject*, ExecState*, PropertyName propertyName, JSValue, unsigned attributes);
- PutWithAttributesFunctionPtr putDirectVirtual;
+ typedef void (*PutWithAttributesFunctionPtr)(JSObject*, ExecState*, PropertyName propertyName, JSValue, unsigned attributes);
+ PutWithAttributesFunctionPtr putDirectVirtual;
- typedef bool (*DefineOwnPropertyFunctionPtr)(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool);
- DefineOwnPropertyFunctionPtr defineOwnProperty;
+ typedef bool (*DefineOwnPropertyFunctionPtr)(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool);
+ DefineOwnPropertyFunctionPtr defineOwnProperty;
- typedef bool (*GetOwnPropertyDescriptorFunctionPtr)(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
- GetOwnPropertyDescriptorFunctionPtr getOwnPropertyDescriptor;
- };
+ typedef bool (*GetOwnPropertyDescriptorFunctionPtr)(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+ GetOwnPropertyDescriptorFunctionPtr getOwnPropertyDescriptor;
+};
#define CREATE_MEMBER_CHECKER(member) \
-template <typename T> \
-struct MemberCheck##member { \
- struct Fallback { \
- void member(...); \
- }; \
- struct Derived : T, Fallback { }; \
- template <typename U, U> struct Check; \
- typedef char Yes[2]; \
- typedef char No[1]; \
- template <typename U> \
- static No &func(Check<void (Fallback::*)(...), &U::member>*); \
- template <typename U> \
- static Yes &func(...); \
- enum { has = sizeof(func<Derived>(0)) == sizeof(Yes) }; \
-}
+ template <typename T> \
+ struct MemberCheck##member { \
+ struct Fallback { \
+ void member(...); \
+ }; \
+ struct Derived : T, Fallback { }; \
+ template <typename U, U> struct Check; \
+ typedef char Yes[2]; \
+ typedef char No[1]; \
+ template <typename U> \
+ static No &func(Check<void (Fallback::*)(...), &U::member>*); \
+ template <typename U> \
+ static Yes &func(...); \
+ enum { has = sizeof(func<Derived>(0)) == sizeof(Yes) }; \
+ }
#define HAS_MEMBER_NAMED(klass, name) (MemberCheck##name<klass>::has)
@@ -141,54 +141,54 @@ struct MemberCheck##member { \
}, \
ClassName::TypedArrayStorageType
- struct ClassInfo {
- /**
- * A string denoting the class name. Example: "Window".
- */
- const char* className;
-
- /**
- * Pointer to the class information of the base class.
- * 0L if there is none.
- */
- const ClassInfo* parentClass;
- /**
- * Static hash-table of properties.
- * For classes that can be used from multiple threads, it is accessed via a getter function that would typically return a pointer to thread-specific value.
- */
- const HashTable* propHashTable(ExecState* exec) const
- {
- if (classPropHashTableGetterFunction)
- return classPropHashTableGetterFunction(exec);
- return staticPropHashTable;
- }
+struct ClassInfo {
+ /**
+ * A string denoting the class name. Example: "Window".
+ */
+ const char* className;
+
+ /**
+ * Pointer to the class information of the base class.
+ * 0L if there is none.
+ */
+ const ClassInfo* parentClass;
+ /**
+ * Static hash-table of properties.
+ * For classes that can be used from multiple threads, it is accessed via a getter function that would typically return a pointer to thread-specific value.
+ */
+ const HashTable* propHashTable(ExecState* exec) const
+ {
+ if (classPropHashTableGetterFunction)
+ return classPropHashTableGetterFunction(exec);
+ return staticPropHashTable;
+ }
- bool isSubClassOf(const ClassInfo* other) const
- {
- for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
- if (ci == other)
- return true;
- }
- return false;
+ bool isSubClassOf(const ClassInfo* other) const
+ {
+ for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
+ if (ci == other)
+ return true;
}
-
- bool hasStaticProperties() const
- {
- for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
- if (ci->staticPropHashTable || ci->classPropHashTableGetterFunction)
- return true;
- }
- return false;
+ return false;
+ }
+
+ bool hasStaticProperties() const
+ {
+ for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
+ if (ci->staticPropHashTable || ci->classPropHashTableGetterFunction)
+ return true;
}
+ return false;
+ }
- const HashTable* staticPropHashTable;
- typedef const HashTable* (*ClassPropHashTableGetterFunction)(ExecState*);
- const ClassPropHashTableGetterFunction classPropHashTableGetterFunction;
+ const HashTable* staticPropHashTable;
+ typedef const HashTable* (*ClassPropHashTableGetterFunction)(ExecState*);
+ const ClassPropHashTableGetterFunction classPropHashTableGetterFunction;
- MethodTable methodTable;
+ MethodTable methodTable;
- TypedArrayType typedArrayStorageType;
- };
+ TypedArrayType typedArrayStorageType;
+};
} // namespace JSC
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..733de42d6 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 CacheMap {
+ typedef typename HashMap<KeyType, unsigned>::iterator iterator;
+public:
+ CacheMap()
+ : m_randomGenerator((static_cast<uint32_t>(randomNumber() * std::numeric_limits<uint32_t>::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;
+ CacheMap<CodeBlockKey, Strong<UnlinkedCodeBlock>, kMaxCodeBlockEntries> m_cachedCodeBlocks;
+ CacheMap<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable>, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions;
+ CacheMap<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..c1c044b0e 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)
{
@@ -752,6 +752,7 @@ namespace JSC {
: Base(globalData, scope->globalObject()->functionStructure())
, m_executable(globalData, this, executable)
, m_scope(globalData, this, scope)
+ , m_inheritorIDWatchpoint(InitializedBlind) // See comment in JSFunction.cpp concerning the reason for using InitializedBlind as opposed to InitializedWatching.
{
}
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/JSBoundFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
index d8f611477..bb1af9d20 100644
--- a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
@@ -31,8 +31,6 @@
namespace JSC {
-ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSBoundFunction);
-
const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSBoundFunction) };
EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState* exec)
@@ -88,6 +86,11 @@ JSBoundFunction* JSBoundFunction::create(ExecState* exec, JSGlobalObject* global
return function;
}
+void JSBoundFunction::destroy(JSCell* cell)
+{
+ static_cast<JSBoundFunction*>(cell)->JSBoundFunction::~JSBoundFunction();
+}
+
bool JSBoundFunction::customHasInstance(JSObject* object, ExecState* exec, JSValue value)
{
return jsCast<JSBoundFunction*>(object)->m_targetFunction->hasInstance(exec, value);
diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.h b/Source/JavaScriptCore/runtime/JSBoundFunction.h
index 05a6ad8e1..886021940 100644
--- a/Source/JavaScriptCore/runtime/JSBoundFunction.h
+++ b/Source/JavaScriptCore/runtime/JSBoundFunction.h
@@ -38,6 +38,8 @@ public:
typedef JSFunction Base;
static JSBoundFunction* create(ExecState*, JSGlobalObject*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int, const String&);
+
+ static void destroy(JSCell*);
static bool customHasInstance(JSObject*, ExecState*, JSValue);
diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h
index 3b37613d1..b28fedd8d 100644
--- a/Source/JavaScriptCore/runtime/JSCell.h
+++ b/Source/JavaScriptCore/runtime/JSCell.h
@@ -28,9 +28,8 @@
#include "ConstructData.h"
#include "Heap.h"
#include "JSLock.h"
-#include "JSValueInlineMethods.h"
+#include "JSValueInlines.h"
#include "SlotVisitor.h"
-#include "SlotVisitorInlineMethods.h"
#include "TypedArrayDescriptor.h"
#include "WriteBarrier.h"
#include <wtf/Noncopyable.h>
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index 891a23930..0a98e7c13 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -48,8 +48,6 @@ EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec)
return throwVMError(exec, createNotAConstructorError(exec, exec->callee()));
}
-ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFunction);
-
const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFunction) };
bool JSFunction::isHostFunctionNonInline() const
@@ -76,10 +74,25 @@ JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, in
return function;
}
+void JSFunction::destroy(JSCell* cell)
+{
+ static_cast<JSFunction*>(cell)->JSFunction::~JSFunction();
+}
+
JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
: Base(exec->globalData(), structure)
, m_executable()
, m_scope(exec->globalData(), this, globalObject)
+ // We initialize blind so that changes to the prototype after function creation but before
+ // the optimizer kicks in don't disable optimizations. Once the optimizer kicks in, the
+ // watchpoint will start watching and any changes will both force deoptimization and disable
+ // future attempts to optimize. This is necessary because we are guaranteed that the
+ // inheritorID is changed exactly once prior to optimizations kicking in. We could be
+ // smarter and count the number of times the prototype is clobbered and only optimize if it
+ // was clobbered exactly once, but that seems like overkill. In almost all cases it will be
+ // clobbered once, and if it's clobbered more than once, that will probably only occur
+ // before we started optimizing, anyway.
+ , m_inheritorIDWatchpoint(InitializedBlind)
{
}
@@ -340,6 +353,7 @@ void JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, J
PropertySlot slot;
thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
thisObject->m_cachedInheritorID.clear();
+ thisObject->m_inheritorIDWatchpoint.notifyWrite();
// Don't allow this to be cached, since a [[Put]] must clear m_cachedInheritorID.
PutPropertySlot dontCache;
Base::put(thisObject, exec, propertyName, value, dontCache);
@@ -386,6 +400,7 @@ bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNa
PropertySlot slot;
thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
thisObject->m_cachedInheritorID.clear();
+ thisObject->m_inheritorIDWatchpoint.notifyWrite();
return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
}
diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h
index c1f066585..322ee58e3 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.h
+++ b/Source/JavaScriptCore/runtime/JSFunction.h
@@ -25,7 +25,9 @@
#define JSFunction_h
#include "InternalFunction.h"
+#include "JSDestructibleObject.h"
#include "JSScope.h"
+#include "Watchpoint.h"
namespace JSC {
@@ -46,14 +48,14 @@ namespace JSC {
JS_EXPORT_PRIVATE String getCalculatedDisplayName(CallFrame*, JSObject*);
- class JSFunction : public JSNonFinalObject {
+ class JSFunction : public JSDestructibleObject {
friend class JIT;
friend class DFG::SpeculativeJIT;
friend class DFG::JITCompiler;
friend class JSGlobalData;
public:
- typedef JSNonFinalObject Base;
+ typedef JSDestructibleObject Base;
JS_EXPORT_PRIVATE static JSFunction* create(ExecState*, JSGlobalObject*, int length, const String& name, NativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
@@ -66,6 +68,8 @@ namespace JSC {
return function;
}
+ static void destroy(JSCell*);
+
JS_EXPORT_PRIVATE String name(ExecState*);
JS_EXPORT_PRIVATE String displayName(ExecState*);
const String calculatedDisplayName(ExecState*);
@@ -129,6 +133,21 @@ namespace JSC {
return m_cachedInheritorID.get();
}
+ Structure* tryGetKnownInheritorID()
+ {
+ if (!m_cachedInheritorID)
+ return 0;
+ if (m_inheritorIDWatchpoint.hasBeenInvalidated())
+ return 0;
+ return m_cachedInheritorID.get();
+ }
+
+ void addInheritorIDWatchpoint(Watchpoint* watchpoint)
+ {
+ ASSERT(tryGetKnownInheritorID());
+ m_inheritorIDWatchpoint.add(watchpoint);
+ }
+
static size_t offsetOfCachedInheritorID()
{
return OBJECT_OFFSETOF(JSFunction, m_cachedInheritorID);
@@ -169,6 +188,7 @@ namespace JSC {
WriteBarrier<ExecutableBase> m_executable;
WriteBarrier<JSScope> m_scope;
WriteBarrier<Structure> m_cachedInheritorID;
+ InlineWatchpointSet m_inheritorIDWatchpoint;
};
inline bool JSValue::isFunction() const
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
index 4dca5b0f6..74429c7a7 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -507,17 +507,17 @@ void JSGlobalData::dumpRegExpTrace()
RTTraceList::iterator iter = ++m_rtTraceList->begin();
if (iter != m_rtTraceList->end()) {
- dataLog("\nRegExp Tracing\n");
- dataLog(" match() matches\n");
- dataLog("Regular Expression JIT Address calls found\n");
- dataLog("----------------------------------------+----------------+----------+----------\n");
+ dataLogF("\nRegExp Tracing\n");
+ dataLogF(" match() matches\n");
+ dataLogF("Regular Expression JIT Address calls found\n");
+ dataLogF("----------------------------------------+----------------+----------+----------\n");
unsigned reCount = 0;
for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
(*iter)->printTraceData();
- dataLog("%d Regular Expressions\n", reCount);
+ dataLogF("%d Regular Expressions\n", reCount);
}
m_rtTraceList->clear();
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index c466a2b04..6f20f0e93 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())));
@@ -252,8 +259,6 @@ void JSGlobalObject::reset(JSValue prototype)
m_regExpPrototype.set(exec->globalData(), this, RegExpPrototype::create(exec, this, RegExpPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()), emptyRegex));
m_regExpStructure.set(exec->globalData(), this, RegExpObject::createStructure(exec->globalData(), this, m_regExpPrototype.get()));
- m_methodCallDummy.set(exec->globalData(), this, constructEmptyObject(exec));
-
m_errorPrototype.set(exec->globalData(), this, ErrorPrototype::create(exec, this, ErrorPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
m_errorStructure.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), this, m_errorPrototype.get()));
@@ -360,7 +365,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 +419,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.
@@ -428,6 +435,14 @@ void JSGlobalObject::haveABadTime(JSGlobalData& globalData)
}
}
+bool JSGlobalObject::arrayPrototypeChainIsSane()
+{
+ return !hasIndexedProperties(m_arrayPrototype->structure()->indexingType())
+ && m_arrayPrototype->prototype() == m_objectPrototype.get()
+ && !hasIndexedProperties(m_objectPrototype->structure()->indexingType())
+ && m_objectPrototype->prototype().isNull();
+}
+
void JSGlobalObject::createThrowTypeError(ExecState* exec)
{
JSFunction* thrower = JSFunction::create(exec, this, 0, String(), globalFuncThrowTypeError);
@@ -457,7 +472,6 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_globalThis);
- visitor.append(&thisObject->m_methodCallDummy);
visitor.append(&thisObject->m_regExpConstructor);
visitor.append(&thisObject->m_errorConstructor);
@@ -488,9 +502,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..e6edd0be7 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"
@@ -99,7 +100,6 @@ namespace JSC {
Register m_globalCallFrame[JSStack::CallFrameHeaderSize];
WriteBarrier<JSObject> m_globalThis;
- WriteBarrier<JSObject> m_methodCallDummy;
WriteBarrier<RegExpConstructor> m_regExpConstructor;
WriteBarrier<ErrorConstructor> m_errorConstructor;
@@ -130,9 +130,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;
@@ -268,21 +271,31 @@ namespace JSC {
RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); }
- JSObject* methodCallDummy() const { return m_methodCallDummy.get(); }
-
Structure* withScopeStructure() const { return m_withScopeStructure.get(); }
Structure* strictEvalActivationStructure() const { return m_strictEvalActivationStructure.get(); }
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(); }
@@ -317,6 +330,8 @@ namespace JSC {
}
void haveABadTime(JSGlobalData&);
+
+ bool arrayPrototypeChainIsSane();
void setProfileGroup(unsigned value) { createRareDataIfNeeded(); m_rareData->profileGroup = value; }
unsigned profileGroup() const
@@ -450,22 +465,27 @@ namespace JSC {
return prototypeForLookup(exec->lexicalGlobalObject());
}
- inline StructureChain* Structure::prototypeChain(ExecState* exec) const
+ inline StructureChain* Structure::prototypeChain(JSGlobalData& globalData, JSGlobalObject* globalObject) const
{
// We cache our prototype chain so our clients can share it.
- if (!isValid(exec, m_cachedPrototypeChain.get())) {
- JSValue prototype = prototypeForLookup(exec);
- m_cachedPrototypeChain.set(exec->globalData(), this, StructureChain::create(exec->globalData(), prototype.isNull() ? 0 : asObject(prototype)->structure()));
+ if (!isValid(globalObject, m_cachedPrototypeChain.get())) {
+ JSValue prototype = prototypeForLookup(globalObject);
+ m_cachedPrototypeChain.set(globalData, this, StructureChain::create(globalData, prototype.isNull() ? 0 : asObject(prototype)->structure()));
}
return m_cachedPrototypeChain.get();
}
- inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
+ inline StructureChain* Structure::prototypeChain(ExecState* exec) const
+ {
+ return prototypeChain(exec->globalData(), exec->lexicalGlobalObject());
+ }
+
+ inline bool Structure::isValid(JSGlobalObject* globalObject, StructureChain* cachedPrototypeChain) const
{
if (!cachedPrototypeChain)
return false;
- JSValue prototype = prototypeForLookup(exec);
+ JSValue prototype = prototypeForLookup(globalObject);
WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head();
while(*cachedStructure && !prototype.isNull()) {
if (asObject(prototype)->structure() != cachedStructure->get())
@@ -476,6 +496,11 @@ namespace JSC {
return prototype.isNull() && !*cachedStructure;
}
+ inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
+ {
+ return isValid(exec->lexicalGlobalObject(), cachedPrototypeChain);
+ }
+
inline JSGlobalObject* ExecState::dynamicGlobalObject()
{
if (this == lexicalGlobalObject()->globalExec())
@@ -497,34 +522,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/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
index 7ac76d350..1010ad2b7 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
@@ -52,7 +52,7 @@ namespace JSC {
static JSValue encode(ExecState* exec, const char* doNotEscape)
{
- CString cstr = exec->argument(0).toString(exec)->value(exec).utf8(true);
+ CString cstr = exec->argument(0).toString(exec)->value(exec).utf8(String::StrictConversion);
if (!cstr.data())
return throwError(exec, createURIError(exec, ASCIILiteral("String contained an illegal UTF-16 sequence.")));
diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp
index 85dbdfedb..5e3d12c92 100644
--- a/Source/JavaScriptCore/runtime/JSLock.cpp
+++ b/Source/JavaScriptCore/runtime/JSLock.cpp
@@ -74,7 +74,9 @@ JSLockHolder::~JSLockHolder()
}
JSLock::JSLock()
- : m_lockCount(0)
+ : m_ownerThread(0)
+ , m_lockCount(0)
+ , m_lockDropDepth(0)
{
m_spinLock.Init();
}
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 6a3fb84e4..564093e33 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())
@@ -332,26 +356,30 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
putByIndex(thisObject, exec, i, value, slot.isStrictMode());
return;
}
-
+
// Check if there are any setters or getters in the prototype chain
JSValue prototype;
if (propertyName != exec->propertyNames().underscoreProto) {
for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
prototype = obj->prototype();
if (prototype.isNull()) {
- if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
+ ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName));
+ if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value))
+ && slot.isStrictMode())
throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
return;
}
}
}
- for (JSObject* obj = thisObject; ; obj = asObject(prototype)) {
+ JSObject* obj;
+ for (obj = thisObject; ; obj = asObject(prototype)) {
unsigned attributes;
JSCell* specificValue;
PropertyOffset offset = obj->structure()->get(globalData, propertyName, attributes, specificValue);
if (isValidOffset(offset)) {
if (attributes & ReadOnly) {
+ ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject);
if (slot.isStrictMode())
throwError(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
return;
@@ -359,6 +387,8 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
JSValue gs = obj->getDirectOffset(offset);
if (gs.isGetterSetter()) {
+ ASSERT(attributes & Accessor);
+ ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject);
JSObject* setterFunc = asGetterSetter(gs)->setter();
if (!setterFunc) {
if (slot.isStrictMode())
@@ -374,7 +404,8 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
// If this is WebCore's global object then we need to substitute the shell.
call(exec, setterFunc, callType, callData, thisObject->methodTable()->toThisObject(thisObject, exec), args);
return;
- }
+ } else
+ ASSERT(!(attributes & Accessor));
// If there's an existing property on the object or one of its
// prototypes it should be replaced, so break here.
@@ -386,6 +417,7 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
break;
}
+ ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject);
if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
return;
@@ -405,6 +437,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 +463,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 +578,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 +608,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 +618,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 +683,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 +728,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 +796,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 +885,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 +1043,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 +1050,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 +1074,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 +1098,7 @@ void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData)
}
default:
- ASSERT_NOT_REACHED();
+ CRASH();
break;
}
}
@@ -877,8 +1265,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 +1277,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 +1456,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 +1471,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 +1872,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 +1886,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 +1896,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 +2025,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 +2172,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 +2254,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 +2356,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 +2403,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 +2418,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..4f7f4700b 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -39,6 +39,7 @@
#include "Structure.h"
#include "JSGlobalData.h"
#include "JSString.h"
+#include "SlotVisitorInlines.h"
#include "SparseArrayValueMap.h"
#include <wtf/StdLibExtras.h>
@@ -151,30 +152,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 +201,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 +225,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:
@@ -242,11 +242,21 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_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 +289,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 +311,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 +327,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 +342,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 +378,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 +428,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 +445,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 +645,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 +691,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 +751,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 +805,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 +847,7 @@ protected:
WriteBarrier<Unknown>* currentIndexingData()
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->contiguous();
@@ -732,10 +860,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 +903,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 +930,8 @@ private:
void isObject();
void isString();
+ Butterfly* createInitialIndexedStorage(JSGlobalData&, unsigned length, size_t elementSize);
+
ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*);
template<PutMode>
@@ -800,11 +954,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;
@@ -1152,6 +1313,8 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p
// See comment on setNewProperty call below.
if (!specificFunction)
slot.setNewProperty(this, offset);
+ if (attributes & ReadOnly)
+ structure()->setContainsReadOnlyProperties();
return true;
}
@@ -1219,6 +1382,8 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p
// so leave the slot in an uncachable state.
if (!specificFunction)
slot.setNewProperty(this, offset);
+ if (attributes & ReadOnly)
+ structure->setContainsReadOnlyProperties();
return true;
}
diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp
index e7f8cad17..d9253730f 100644
--- a/Source/JavaScriptCore/runtime/JSValue.cpp
+++ b/Source/JavaScriptCore/runtime/JSValue.cpp
@@ -214,10 +214,18 @@ char* JSValue::description() const
snprintf(description, size, "Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble());
#endif
} else if (isCell()) {
- snprintf(
- description, size, "Cell: %p (%p: %s, %s)",
- asCell(), asCell()->structure(), asCell()->structure()->classInfo()->className,
- indexingTypeToString(asCell()->structure()->indexingTypeIncludingHistory()));
+ if (asCell()->inherits(&Structure::s_info)) {
+ Structure* structure = jsCast<Structure*>(asCell());
+ snprintf(
+ description, size, "Structure: %p: %s, %s",
+ structure, structure->classInfo()->className,
+ indexingTypeToString(structure->indexingTypeIncludingHistory()));
+ } else {
+ snprintf(
+ 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");
else if (isFalse())
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..7301bf6ec 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 {
@@ -86,6 +86,7 @@ namespace JSC {
if (ropeBuilder.length() < oldLength) // True for overflow
return throwOutOfMemoryError(exec);
+ oldLength = ropeBuilder.length();
}
return ropeBuilder.release();
@@ -105,6 +106,7 @@ namespace JSC {
if (ropeBuilder.length() < oldLength) // True for overflow
return throwOutOfMemoryError(exec);
+ oldLength = ropeBuilder.length();
}
return ropeBuilder.release();
@@ -356,6 +358,23 @@ namespace JSC {
}
}
+ inline bool isPrototypeChainNormalized(JSGlobalObject* globalObject, Structure* structure)
+ {
+ for (;;) {
+ if (structure->typeInfo().type() == ProxyType)
+ return false;
+
+ JSValue v = structure->prototypeForLookup(globalObject);
+ if (v.isNull())
+ return true;
+
+ structure = v.asCell()->structure();
+
+ if (structure->isDictionary())
+ return false;
+ }
+ }
+
} // namespace JSC
#endif // Operations_h
diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h
index d6d8c66c8..99a5f85a2 100644
--- a/Source/JavaScriptCore/runtime/Options.h
+++ b/Source/JavaScriptCore/runtime/Options.h
@@ -66,6 +66,8 @@ namespace JSC {
v(bool, useDFGJIT, true) \
v(bool, useRegExpJIT, true) \
\
+ v(bool, forceDFGCodeBlockLiveness, false) \
+ \
/* showDisassembly implies showDFGDisassembly. */ \
v(bool, showDisassembly, false) \
v(bool, showDFGDisassembly, false) \
diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp
index 7757274f1..3229f5207 100644
--- a/Source/JavaScriptCore/runtime/RegExp.cpp
+++ b/Source/JavaScriptCore/runtime/RegExp.cpp
@@ -520,24 +520,24 @@ void RegExp::matchCompareWithInterpreter(const String& s, int startOffset, int*
differences++;
if (differences) {
- dataLog("RegExp Discrepency for /%s/\n string input ", pattern().utf8().data());
+ dataLogF("RegExp Discrepency for /%s/\n string input ", pattern().utf8().data());
unsigned segmentLen = s.length() - static_cast<unsigned>(startOffset);
- dataLog((segmentLen < 150) ? "\"%s\"\n" : "\"%148s...\"\n", s.utf8().data() + startOffset);
+ dataLogF((segmentLen < 150) ? "\"%s\"\n" : "\"%148s...\"\n", s.utf8().data() + startOffset);
if (jitResult != interpreterResult) {
- dataLog(" JIT result = %d, blah interpreted result = %d\n", jitResult, interpreterResult);
+ dataLogF(" JIT result = %d, blah interpreted result = %d\n", jitResult, interpreterResult);
differences--;
} else {
- dataLog(" Correct result = %d\n", jitResult);
+ dataLogF(" Correct result = %d\n", jitResult);
}
if (differences) {
for (unsigned j = 2, i = 0; i < m_numSubpatterns; j +=2, i++) {
if (offsetVector[j] != interpreterOffsetVector[j])
- dataLog(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j, offsetVector[j], j, interpreterOffsetVector[j]);
+ dataLogF(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j, offsetVector[j], j, interpreterOffsetVector[j]);
if ((offsetVector[j] >= 0) && (offsetVector[j+1] != interpreterOffsetVector[j+1]))
- dataLog(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j+1, offsetVector[j+1], j+1, interpreterOffsetVector[j+1]);
+ dataLogF(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j+1, offsetVector[j+1], j+1, interpreterOffsetVector[j+1]);
}
}
}
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/SamplingCounter.cpp b/Source/JavaScriptCore/runtime/SamplingCounter.cpp
index abed763ca..9826b88e4 100644
--- a/Source/JavaScriptCore/runtime/SamplingCounter.cpp
+++ b/Source/JavaScriptCore/runtime/SamplingCounter.cpp
@@ -35,10 +35,10 @@ void AbstractSamplingCounter::dump()
{
#if ENABLE(SAMPLING_COUNTERS)
if (s_abstractSamplingCounterChain != &s_abstractSamplingCounterChainEnd) {
- dataLog("\nSampling Counter Values:\n");
+ dataLogF("\nSampling Counter Values:\n");
for (AbstractSamplingCounter* currCounter = s_abstractSamplingCounterChain; (currCounter != &s_abstractSamplingCounterChainEnd); currCounter = currCounter->m_next)
- dataLog("\t%s\t: %lld\n", currCounter->m_name, currCounter->m_counter);
- dataLog("\n\n");
+ dataLogF("\t%s\t: %lld\n", currCounter->m_name, currCounter->m_counter);
+ dataLogF("\n\n");
}
s_completed = true;
#endif
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..9ffe3b060 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -135,17 +135,17 @@ void Structure::dumpStatistics()
}
}
- dataLog("Number of live Structures: %d\n", liveStructureSet.size());
- dataLog("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
- dataLog("Number of Structures that are leaf nodes: %d\n", numberLeaf);
- dataLog("Number of Structures that singletons: %d\n", numberSingletons);
- dataLog("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps);
-
- dataLog("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure)));
- dataLog("Size of sum of all property maps: %d\n", totalPropertyMapsSize);
- dataLog("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size()));
+ dataLogF("Number of live Structures: %d\n", liveStructureSet.size());
+ dataLogF("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
+ dataLogF("Number of Structures that are leaf nodes: %d\n", numberLeaf);
+ dataLogF("Number of Structures that singletons: %d\n", numberSingletons);
+ dataLogF("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps);
+
+ dataLogF("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure)));
+ dataLogF("Size of sum of all property maps: %d\n", totalPropertyMapsSize);
+ dataLogF("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size()));
#else
- dataLog("Dumping Structure statistics is not enabled.\n");
+ dataLogF("Dumping Structure statistics is not enabled.\n");
#endif
}
@@ -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;
+ }
}
}
@@ -694,11 +695,11 @@ static PropertyMapStatisticsExitLogger logger;
PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
{
- dataLog("\nJSC::PropertyMap statistics\n\n");
- dataLog("%d probes\n", numProbes);
- dataLog("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);
- dataLog("%d rehashes\n", numRehashes);
- dataLog("%d removes\n", numRemoves);
+ dataLogF("\nJSC::PropertyMap statistics\n\n");
+ dataLogF("%d probes\n", numProbes);
+ dataLogF("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);
+ dataLogF("%d rehashes\n", numRehashes);
+ dataLogF("%d removes\n", numRemoves);
}
#endif
@@ -861,6 +862,32 @@ void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&thisObject->m_objectToStringValue);
}
+bool Structure::prototypeChainMayInterceptStoreTo(JSGlobalData& globalData, PropertyName propertyName)
+{
+ unsigned i = propertyName.asIndex();
+ if (i != PropertyName::NotAnIndex)
+ return anyObjectInChainMayInterceptIndexedAccesses();
+
+ for (Structure* current = this; ;) {
+ JSValue prototype = current->storedPrototype();
+ if (prototype.isNull())
+ return false;
+
+ current = prototype.asCell()->structure();
+
+ unsigned attributes;
+ JSCell* specificValue;
+ PropertyOffset offset = current->get(globalData, propertyName, attributes, specificValue);
+ if (!JSC::isValidOffset(offset))
+ continue;
+
+ if (attributes & (ReadOnly | Accessor))
+ return true;
+
+ return false;
+ }
+}
+
#if DO_PROPERTYMAP_CONSTENCY_CHECK
void PropertyTable::checkConsistency()
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index 2b25803a6..6e4402c52 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -166,9 +166,15 @@ namespace JSC {
JSValue prototypeForLookup(ExecState*) const;
JSValue prototypeForLookup(JSGlobalObject*) const;
JSValue prototypeForLookup(CodeBlock*) const;
+ StructureChain* prototypeChain(JSGlobalData&, JSGlobalObject*) const;
StructureChain* prototypeChain(ExecState*) const;
static void visitChildren(JSCell*, SlotVisitor&);
-
+
+ // Will just the prototype chain intercept this property access?
+ bool prototypeChainMayInterceptStoreTo(JSGlobalData&, PropertyName);
+
+ bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; }
+
Structure* previousID() const
{
ASSERT(structure()->classInfo() == &s_info);
@@ -397,6 +403,7 @@ namespace JSC {
return numberOfSlotsForLastOffset(m_offset, m_typeInfo.type());
}
+ bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const;
bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
void pin();
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));
diff --git a/Source/JavaScriptCore/tools/CodeProfile.cpp b/Source/JavaScriptCore/tools/CodeProfile.cpp
index 0020c7285..b3c4ff448 100644
--- a/Source/JavaScriptCore/tools/CodeProfile.cpp
+++ b/Source/JavaScriptCore/tools/CodeProfile.cpp
@@ -143,7 +143,7 @@ void CodeProfile::sample(void* pc, void** framePointer)
void CodeProfile::report()
{
- dataLog("<CodeProfiling %s:%d>\n", m_file.data(), m_lineNo);
+ dataLogF("<CodeProfiling %s:%d>\n", m_file.data(), m_lineNo);
// How many frames of C-code to print - 0, if not verbose, 1 if verbose, up to 1024 if very verbose.
unsigned recursionLimit = CodeProfiling::beVeryVerbose() ? 1024 : CodeProfiling::beVerbose();
@@ -180,13 +180,13 @@ void CodeProfile::report()
}
// Output the profile tree.
- dataLog("Total samples: %lld\n", static_cast<long long>(profile.childCount()));
+ dataLogF("Total samples: %lld\n", static_cast<long long>(profile.childCount()));
profile.dump();
for (size_t i = 0 ; i < m_children.size(); ++i)
m_children[i]->report();
- dataLog("</CodeProfiling %s:%d>\n", m_file.data(), m_lineNo);
+ dataLogF("</CodeProfiling %s:%d>\n", m_file.data(), m_lineNo);
}
}
diff --git a/Source/JavaScriptCore/tools/ProfileTreeNode.h b/Source/JavaScriptCore/tools/ProfileTreeNode.h
index 7b5a95ec4..4daa7df4c 100644
--- a/Source/JavaScriptCore/tools/ProfileTreeNode.h
+++ b/Source/JavaScriptCore/tools/ProfileTreeNode.h
@@ -95,8 +95,8 @@ private:
// Print the number of samples, the name of this node, and the number of samples that are stack-top
// in this node (samples directly within this node, excluding samples in children.
for (unsigned i = 0; i < indent; ++i)
- dataLog(" ");
- dataLog("% 8lld: %s (%lld stack top)\n",
+ dataLogF(" ");
+ dataLogF("% 8lld: %s (%lld stack top)\n",
static_cast<long long>(entry->value.count()),
entry->key.utf8().data(),
static_cast<long long>(entry->value.count() - entry->value.childCount()));
diff --git a/Source/JavaScriptCore/yarr/YarrInterpreter.cpp b/Source/JavaScriptCore/yarr/YarrInterpreter.cpp
index 5c2a287c8..31603f6d3 100644
--- a/Source/JavaScriptCore/yarr/YarrInterpreter.cpp
+++ b/Source/JavaScriptCore/yarr/YarrInterpreter.cpp
@@ -1650,10 +1650,10 @@ public:
#ifndef NDEBUG
void dumpDisjunction(ByteDisjunction* disjunction)
{
- dataLog("ByteDisjunction(%p):\n\t", disjunction);
+ dataLogF("ByteDisjunction(%p):\n\t", disjunction);
for (unsigned i = 0; i < disjunction->terms.size(); ++i)
- dataLog("{ %d } ", disjunction->terms[i].type);
- dataLog("\n");
+ dataLogF("{ %d } ", disjunction->terms[i].type);
+ dataLogF("\n");
}
#endif